plugin.cpp 30.3 KB
Newer Older
1 2 3
/*****************************************************************************
 * plugin.cpp: ActiveX control for VLC
 *****************************************************************************
4
 * Copyright (C) 2006 the VideoLAN team
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
 *****************************************************************************/

#include "plugin.h"

#include "oleobject.h"
#include "olecontrol.h"
#include "oleinplaceobject.h"
#include "oleinplaceactiveobject.h"
#include "persistpropbag.h"
#include "persiststreaminit.h"
#include "persiststorage.h"
#include "provideclassinfo.h"
#include "connectioncontainer.h"
#include "objectsafety.h"
#include "vlccontrol.h"
36
#include "vlccontrol2.h"
37
#include "viewobject.h"
Damien Fouilleul's avatar
 
Damien Fouilleul committed
38
#include "dataobject.h"
39
#include "supporterrorinfo.h"
40 41 42 43 44

#include "utils.h"

#include <string.h>
#include <winreg.h>
45 46 47 48
#include <winuser.h>
#include <servprov.h>
#include <shlwapi.h>
#include <wininet.h>
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67

using namespace std;

////////////////////////////////////////////////////////////////////////
//class factory

static LRESULT CALLBACK VLCInPlaceClassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    VLCPlugin *p_instance = reinterpret_cast<VLCPlugin *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));

    switch( uMsg )
    {
        case WM_ERASEBKGND:
            return 1L;

        case WM_PAINT:
            PAINTSTRUCT ps;
            RECT pr;
            if( GetUpdateRect(hWnd, &pr, FALSE) )
            {
68 69
                RECT bounds;
                GetClientRect(hWnd, &bounds);
70
                BeginPaint(hWnd, &ps);
71
                p_instance->onPaint(ps.hdc, bounds, pr);
72 73 74 75 76 77 78 79 80
                EndPaint(hWnd, &ps);
            }
            return 0L;

        default:
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
};

81
VLCPluginClass::VLCPluginClass(LONG *p_class_ref, HINSTANCE hInstance, REFCLSID rclsid) :
82
    _p_class_ref(p_class_ref),
Damien Fouilleul's avatar
Damien Fouilleul committed
83
    _hinstance(hInstance),
84
    _classid(rclsid),
Damien Fouilleul's avatar
Damien Fouilleul committed
85
    _inplace_picture(NULL)
86 87 88 89 90
{
    WNDCLASS wClass;

    if( ! GetClassInfo(hInstance, getInPlaceWndClassName(), &wClass) )
    {
91
        wClass.style          = CS_NOCLOSE|CS_DBLCLKS;
92 93 94 95 96 97 98 99 100
        wClass.lpfnWndProc    = VLCInPlaceClassWndProc;
        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  = getInPlaceWndClassName();
101

102 103 104 105 106 107 108
        _inplace_wndclass_atom = RegisterClass(&wClass);
    }
    else
    {
        _inplace_wndclass_atom = 0;
    }

Damien Fouilleul's avatar
 
Damien Fouilleul committed
109 110 111 112 113 114 115 116 117
    HBITMAP hbitmap = (HBITMAP)LoadImage(getHInstance(), TEXT("INPLACE-PICT"), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
    if( NULL != hbitmap )
    {
        PICTDESC pictDesc;

        pictDesc.cbSizeofstruct = sizeof(PICTDESC);
        pictDesc.picType        = PICTYPE_BITMAP;
        pictDesc.bmp.hbitmap    = hbitmap;
        pictDesc.bmp.hpal       = NULL;
118

Damien Fouilleul's avatar
 
Damien Fouilleul committed
119 120 121
        if( FAILED(OleCreatePictureIndirect(&pictDesc, IID_IPicture, TRUE, reinterpret_cast<LPVOID*>(&_inplace_picture))) )
            _inplace_picture = NULL;
    }
122 123 124 125 126 127 128 129
    AddRef();
};

VLCPluginClass::~VLCPluginClass()
{
    if( 0 != _inplace_wndclass_atom )
        UnregisterClass(MAKEINTATOM(_inplace_wndclass_atom), _hinstance);

Damien Fouilleul's avatar
 
Damien Fouilleul committed
130 131
    if( NULL != _inplace_picture )
        _inplace_picture->Release();
132 133 134 135 136 137 138
};

STDMETHODIMP VLCPluginClass::QueryInterface(REFIID riid, void **ppv)
{
    if( NULL == ppv )
        return E_INVALIDARG;

139 140
    if( (IID_IUnknown == riid)
     || (IID_IClassFactory == riid) )
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
    {
        AddRef();
        *ppv = reinterpret_cast<LPVOID>(this);

        return NOERROR;
    }

    *ppv = NULL;

    return E_NOINTERFACE;
};

STDMETHODIMP_(ULONG) VLCPluginClass::AddRef(void)
{
    return InterlockedIncrement(_p_class_ref);
};

STDMETHODIMP_(ULONG) VLCPluginClass::Release(void)
{
    ULONG refcount = InterlockedDecrement(_p_class_ref);
    if( 0 == refcount )
    {
        delete this;
        return 0;
    }
    return refcount;
};

Damien Fouilleul's avatar
 
Damien Fouilleul committed
169
STDMETHODIMP VLCPluginClass::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **ppv)
170 171 172 173 174 175
{
    if( NULL == ppv )
        return E_POINTER;

    *ppv = NULL;

Damien Fouilleul's avatar
 
Damien Fouilleul committed
176
    if( (NULL != pUnkOuter) && (IID_IUnknown != riid) ) {
177
        return CLASS_E_NOAGGREGATION;
Damien Fouilleul's avatar
 
Damien Fouilleul committed
178
    }
179

Damien Fouilleul's avatar
 
Damien Fouilleul committed
180
    VLCPlugin *plugin = new VLCPlugin(this, pUnkOuter);
181 182 183
    if( NULL != plugin )
    {
        HRESULT hr = plugin->QueryInterface(riid, ppv);
184
        // the following will destroy the object if QueryInterface() failed
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
        plugin->Release();
        return hr;
    }
    return E_OUTOFMEMORY;
};

STDMETHODIMP VLCPluginClass::LockServer(BOOL fLock)
{
    if( fLock )
        AddRef();
    else 
        Release();

    return S_OK;
};

////////////////////////////////////////////////////////////////////////

Damien Fouilleul's avatar
 
Damien Fouilleul committed
203
VLCPlugin::VLCPlugin(VLCPluginClass *p_class, LPUNKNOWN pUnkOuter) :
204 205 206
    _inplacewnd(NULL),
    _p_class(p_class),
    _i_ref(1UL),
207
    _p_libvlc(NULL),
208
    _i_codepage(CP_ACP),
209
    _b_usermode(TRUE)
210 211 212 213 214 215 216 217 218 219 220 221 222
{
    p_class->AddRef();

    vlcOleControl = new VLCOleControl(this);
    vlcOleInPlaceObject = new VLCOleInPlaceObject(this);
    vlcOleInPlaceActiveObject = new VLCOleInPlaceActiveObject(this);
    vlcPersistStorage = new VLCPersistStorage(this);
    vlcPersistStreamInit = new VLCPersistStreamInit(this);
    vlcPersistPropertyBag = new VLCPersistPropertyBag(this);
    vlcProvideClassInfo = new VLCProvideClassInfo(this);
    vlcConnectionPointContainer = new VLCConnectionPointContainer(this);
    vlcObjectSafety = new VLCObjectSafety(this);
    vlcControl = new VLCControl(this);
223
    vlcControl2 = new VLCControl2(this);
224
    vlcViewObject = new VLCViewObject(this);
Damien Fouilleul's avatar
 
Damien Fouilleul committed
225
    vlcDataObject = new VLCDataObject(this);
226
    vlcOleObject = new VLCOleObject(this);
227
    vlcSupportErrorInfo = new VLCSupportErrorInfo(this);
Damien Fouilleul's avatar
 
Damien Fouilleul committed
228 229 230 231 232

    // configure controlling IUnknown interface for implemented interfaces
    this->pUnkOuter = (NULL != pUnkOuter) ? pUnkOuter : dynamic_cast<LPUNKNOWN>(this);

    // default picure
233
    _p_pict = p_class->getInPlacePict();
Damien Fouilleul's avatar
Damien Fouilleul committed
234

235 236
    // make sure that persistable properties are initialized
    onInit();
237 238 239 240
};

VLCPlugin::~VLCPlugin()
{
241
    delete vlcSupportErrorInfo;
242
    delete vlcOleObject;
Damien Fouilleul's avatar
 
Damien Fouilleul committed
243
    delete vlcDataObject;
244
    delete vlcViewObject;
245
    delete vlcControl2;
246 247 248 249 250 251 252 253
    delete vlcControl;
    delete vlcConnectionPointContainer;
    delete vlcProvideClassInfo;
    delete vlcPersistPropertyBag;
    delete vlcPersistStreamInit;
    delete vlcPersistStorage;
    delete vlcOleInPlaceActiveObject;
    delete vlcOleInPlaceObject;
254
    delete vlcObjectSafety;
255

256 257 258
    delete vlcOleControl;
    if( _p_pict )
        _p_pict->Release();
Damien Fouilleul's avatar
 
Damien Fouilleul committed
259

Damien Fouilleul's avatar
Damien Fouilleul committed
260
    SysFreeString(_bstr_mrl);
261
    SysFreeString(_bstr_baseurl);
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283

    _p_class->Release();
};

STDMETHODIMP VLCPlugin::QueryInterface(REFIID riid, void **ppv)
{
    if( NULL == ppv )
        return E_INVALIDARG;

    if( IID_IUnknown == riid )
        *ppv = reinterpret_cast<LPVOID>(this);
    else if( IID_IOleObject == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcOleObject);
    else if( IID_IOleControl == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcOleControl);
    else if( IID_IOleWindow == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceObject);
    else if( IID_IOleInPlaceObject == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceObject);
    else if( IID_IOleInPlaceActiveObject == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceActiveObject);
    else if( IID_IPersist == riid )
284
        *ppv = reinterpret_cast<LPVOID>(vlcPersistStreamInit);
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
    else if( IID_IPersistStreamInit == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcPersistStreamInit);
    else if( IID_IPersistStorage == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcPersistStorage);
    else if( IID_IPersistPropertyBag == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcPersistPropertyBag);
    else if( IID_IProvideClassInfo == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcProvideClassInfo);
    else if( IID_IProvideClassInfo2 == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcProvideClassInfo);
    else if( IID_IConnectionPointContainer == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcConnectionPointContainer);
    else if( IID_IObjectSafety == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcObjectSafety);
    else if( IID_IDispatch == riid )
300 301 302
        *ppv = (CLSID_VLCPlugin2 == getClassID()) ?
                reinterpret_cast<LPVOID>(vlcControl2) :
                reinterpret_cast<LPVOID>(vlcControl);
303 304
    else if( IID_IVLCControl == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcControl);
305 306
    else if( IID_IVLCControl2 == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcControl2);
307 308
    else if( IID_IViewObject == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcViewObject);
Damien Fouilleul's avatar
Damien Fouilleul committed
309 310
    else if( IID_IViewObject2 == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcViewObject);
Damien Fouilleul's avatar
 
Damien Fouilleul committed
311 312
    else if( IID_IDataObject == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcDataObject);
313 314
    else if( IID_ISupportErrorInfo == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcSupportErrorInfo);
Damien Fouilleul's avatar
 
Damien Fouilleul committed
315 316 317 318
    else
    {
        *ppv = NULL;
        return E_NOINTERFACE;
Damien Fouilleul's avatar
Damien Fouilleul committed
319
    }
Damien Fouilleul's avatar
 
Damien Fouilleul committed
320 321
    ((LPUNKNOWN)*ppv)->AddRef();
    return NOERROR;
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
};

STDMETHODIMP_(ULONG) VLCPlugin::AddRef(void)
{
    return InterlockedIncrement((LONG *)&_i_ref);
};

STDMETHODIMP_(ULONG) VLCPlugin::Release(void)
{
    if( ! InterlockedDecrement((LONG *)&_i_ref) )
    {
        delete this;
        return 0;
    }
    return _i_ref;
};

//////////////////////////////////////

341
HRESULT VLCPlugin::onInit(void)
342
{
343
    if( NULL == _p_libvlc )
344
    {
345 346 347
        // initialize persistable properties
        _b_autoplay = TRUE;
        _b_autoloop = FALSE;
348 349
        _bstr_baseurl = NULL;
        _bstr_mrl = NULL;
350 351 352
        _b_visible = TRUE;
        _b_mute = FALSE;
        _i_volume = 50;
353
        _i_time   = 0;
354
        _i_backcolor = 0;
355 356 357 358 359 360
        // 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);
361 362 363

        return S_OK;
    }
Damien Fouilleul's avatar
 
Damien Fouilleul committed
364
    return CO_E_ALREADYINITIALIZED;
365
};
366 367 368

HRESULT VLCPlugin::onLoad(void)
{
369
    if( SysStringLen(_bstr_baseurl) == 0 )
370
    {
371
        /*
372 373
        ** 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. 
374
        */
375
        LPOLECLIENTSITE pClientSite;
Damien Fouilleul's avatar
Damien Fouilleul committed
376
        if( SUCCEEDED(vlcOleObject->GetClientSite(&pClientSite)) && (NULL != pClientSite) )
377 378 379 380 381 382 383 384
        {
            IBindCtx *pBC = 0;
            if( SUCCEEDED(CreateBindCtx(0, &pBC)) )
            {
                LPMONIKER pContMoniker = NULL;
                if( SUCCEEDED(pClientSite->GetMoniker(OLEGETMONIKER_ONLYIFTHERE,
                                OLEWHICHMK_CONTAINER, &pContMoniker)) )
                {
385 386
                    LPOLESTR base_url;
                    if( SUCCEEDED(pContMoniker->GetDisplayName(pBC, NULL, &base_url)) )
387
                    {
388 389 390
                        /*
                        ** check that the moniker name is a URL
                        */
391
                        if( UrlIsW(base_url, URLIS_URL) )
392
                        {
393
                            /* copy base URL */
394
                            _bstr_baseurl = SysAllocString(base_url);
395
                        }
396
                        CoTaskMemFree(base_url);
397 398 399 400
                    }
                }
            }
        }
401 402 403 404 405
    }
    setDirty(FALSE);
    return S_OK;
};

406
HRESULT VLCPlugin::getVLCObject(int* i_vlc)
407
{
408 409 410
    libvlc_instance_t *p_libvlc;
    HRESULT result = getVLC(&p_libvlc);
    if( SUCCEEDED(result) )
411
    {
412 413 414 415 416 417 418 419
        *i_vlc = libvlc_get_vlc_id(p_libvlc);
    }
    else
    {
        *i_vlc = 0;
    }
    return result;
}
420

421 422
HRESULT VLCPlugin::getVLC(libvlc_instance_t** pp_libvlc)
{
423 424
    extern HMODULE DllGetModule();

425 426
    if( ! isRunning() )
    {
427 428 429
        /*
        ** default initialization options
        */
430
        char *ppsz_argv[32] = { "vlc" };
431 432
        int   ppsz_argc = 1;

Damien Fouilleul's avatar
Damien Fouilleul committed
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
        char p_progpath[MAX_PATH];
        {
            TCHAR w_progpath[MAX_PATH];
            DWORD len = GetModuleFileName(DllGetModule(), w_progpath, MAX_PATH);
            if( len > 0 )
            {
                len = WideCharToMultiByte(CP_UTF8, 0, w_progpath, len, p_progpath,
                           sizeof(p_progpath)-1, NULL, NULL);
                if( len > 0 )
                {
                    p_progpath[len] = '\0';
                    ppsz_argv[0] = p_progpath;
                }
            }
        }

        ppsz_argv[ppsz_argc++] = "-vv";

451
        HKEY h_key;
Damien Fouilleul's avatar
Damien Fouilleul committed
452
        char p_pluginpath[MAX_PATH];
453
        if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("Software\\VideoLAN\\VLC"),
454 455
                          0, KEY_READ, &h_key ) == ERROR_SUCCESS )
        {
456
            DWORD i_type, i_data = MAX_PATH;
Damien Fouilleul's avatar
Damien Fouilleul committed
457
            TCHAR w_pluginpath[MAX_PATH];
458
            if( RegQueryValueEx( h_key, TEXT("InstallDir"), 0, &i_type,
Damien Fouilleul's avatar
Damien Fouilleul committed
459
                                 (LPBYTE)w_pluginpath, &i_data ) == ERROR_SUCCESS )
460 461 462
            {
                if( i_type == REG_SZ )
                {
Damien Fouilleul's avatar
Damien Fouilleul committed
463 464
                    if( WideCharToMultiByte(CP_UTF8, 0, w_pluginpath, -1, p_pluginpath,
                             sizeof(p_pluginpath)-sizeof("\\plugins")+1, NULL, NULL) )
465
                    {
Damien Fouilleul's avatar
Damien Fouilleul committed
466
                        strcat( p_pluginpath, "\\plugins" );
467
                        ppsz_argv[ppsz_argc++] = "--plugin-path";
Damien Fouilleul's avatar
Damien Fouilleul committed
468
                        ppsz_argv[ppsz_argc++] = p_pluginpath;
469
                    }
470 471 472
                }
            }
            RegCloseKey( h_key );
473 474 475 476 477
        }

        // make sure plugin isn't affected with VLC single instance mode
        ppsz_argv[ppsz_argc++] = "--no-one-instance";

478 479 480
        /* common settings */
        ppsz_argv[ppsz_argc++] = "--no-stats";
        ppsz_argv[ppsz_argc++] = "--no-media-library";
Damien Fouilleul's avatar
Damien Fouilleul committed
481
        ppsz_argv[ppsz_argc++] = "--intf=dummy";
482

483 484 485 486
        // loop mode is a configuration option only
        if( _b_autoloop )
            ppsz_argv[ppsz_argc++] = "--loop";

487 488
        _p_libvlc = libvlc_new(ppsz_argc, ppsz_argv, NULL);
        if( NULL == _p_libvlc )
489
        {
490
            *pp_libvlc = NULL;
491 492 493
            return E_FAIL;
        }

494 495 496 497
        // initial volume setting
        libvlc_audio_set_volume(_p_libvlc, _i_volume, NULL);
        if( _b_mute )
        {
Damien Fouilleul's avatar
Damien Fouilleul committed
498
            libvlc_audio_set_mute(_p_libvlc, TRUE, NULL);
499
        }
500

501
        // initial playlist item
502
        if( SysStringLen(_bstr_mrl) > 0 )
503
        {
504
            char *psz_mrl = NULL;
505 506

            if( SysStringLen(_bstr_baseurl) > 0 )
507
            {
508 509 510 511
                /*
                ** if the MRL a relative URL, we should end up with an absolute URL
                */
                LPWSTR abs_url = CombineURL(_bstr_baseurl, _bstr_mrl);
512
                if( NULL != abs_url )
513
                {
514
                    psz_mrl = CStrFromWSTR(CP_UTF8, abs_url, wcslen(abs_url));
515
                    CoTaskMemFree(abs_url);
516
                }
517 518 519 520
                else
                {
                    psz_mrl = CStrFromBSTR(CP_UTF8, _bstr_mrl);
                }
521 522 523 524 525 526 527
            }
            else
            {
                /*
                ** baseURL is empty, assume MRL is absolute
                */
                psz_mrl = CStrFromBSTR(CP_UTF8, _bstr_mrl);
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542
            }
            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);
543
            }
544
        }
545
    }
546
    *pp_libvlc = _p_libvlc;
547 548 549
    return S_OK;
};

550 551 552 553 554 555 556
void VLCPlugin::setErrorInfo(REFIID riid, const char *description)
{
    vlcSupportErrorInfo->setErrorInfo( getClassID() == CLSID_VLCPlugin2 ?
        OLESTR("VideoLAN.VLCPlugin.2") : OLESTR("VideoLAN.VLCPlugin.1"),
        riid, description );
};

557
HRESULT VLCPlugin::onAmbientChanged(LPUNKNOWN pContainer, DISPID dispID)
558
{
559 560
    VARIANT v;
    switch( dispID )
561
    {
562
        case DISPID_AMBIENT_BACKCOLOR:
563 564 565 566 567 568
            VariantInit(&v);
            V_VT(&v) = VT_I4;
            if( SUCCEEDED(GetObjectProperty(pContainer, dispID, v)) )
            {
                setBackColor(V_I4(&v));
            }
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
            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:
623 624 625
            /*
            ** multiple property change, look up the ones we are interested in
            */
626 627 628 629 630 631 632 633
            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;
634
            if( SUCCEEDED(GetObjectProperty(pContainer, DISPID_AMBIENT_CODEPAGE, v)) )
635 636 637 638
            {
                setCodePage(V_I4(&v));
            }
            break;
639 640 641 642
    }
    return S_OK;
};

643 644
HRESULT VLCPlugin::onClose(DWORD dwSaveOption)
{
645 646 647 648 649
    if( isInPlaceActive() )
    {
        onInPlaceDeactivate();
    }
    if( isRunning() )
650
    {
651
        libvlc_instance_t* p_libvlc = _p_libvlc;
Damien Fouilleul's avatar
 
Damien Fouilleul committed
652

653 654 655 656 657 658 659 660
        IVLCLog *p_log;
    	if( SUCCEEDED(vlcControl2->get_log(&p_log)) )
        {
            // make sure the log is disabled
            p_log->put_verbosity(-1);
            p_log->Release();
        }

661
        _p_libvlc = NULL;
Damien Fouilleul's avatar
 
Damien Fouilleul committed
662
        vlcDataObject->onClose();
663

664
        libvlc_destroy(p_libvlc, NULL );
665 666 667 668 669 670 671 672 673 674 675
    }
    return S_OK;
};

BOOL VLCPlugin::isInPlaceActive(void)
{
    return (NULL != _inplacewnd);
};

HRESULT VLCPlugin::onActivateInPlace(LPMSG lpMesg, HWND hwndParent, LPCRECT lprcPosRect, LPCRECT lprcClipRect)
{
Damien Fouilleul's avatar
Damien Fouilleul committed
676
    RECT clipRect = *lprcClipRect;
677

Damien Fouilleul's avatar
Damien Fouilleul committed
678 679 680
    /*
    ** record keeping of control geometry within container
    */ 
681
    _posRect = *lprcPosRect;
682

Damien Fouilleul's avatar
Damien Fouilleul committed
683 684
    /*
    ** Create a window for in place activated control.
685 686
    ** the window geometry matches the control viewport
    ** within container so that embedded video is always
687
    ** properly displayed.
Damien Fouilleul's avatar
Damien Fouilleul committed
688
    */
689
    _inplacewnd = CreateWindow(_p_class->getInPlaceWndClassName(),
690
            TEXT("VLC Plugin In-Place Window"),
691
            WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,
692 693 694 695
            lprcPosRect->left,
            lprcPosRect->top,
            lprcPosRect->right-lprcPosRect->left,
            lprcPosRect->bottom-lprcPosRect->top,
696 697 698 699 700 701 702 703 704 705 706
            hwndParent,
            0,
            _p_class->getHInstance(),
            NULL
           );

    if( NULL == _inplacewnd )
        return E_FAIL;

    SetWindowLongPtr(_inplacewnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));

707 708
    /* change cliprect coordinates system relative to window bounding rect */
    OffsetRect(&clipRect, -lprcPosRect->left, -lprcPosRect->top);
709

710 711
    HRGN clipRgn = CreateRectRgnIndirect(&clipRect);
    SetWindowRgn(_inplacewnd, clipRgn, TRUE);
712

713
    if( _b_usermode )
714
    {
715
        /* will run vlc if not done already */
716 717
        libvlc_instance_t* p_libvlc;
        HRESULT result = getVLC(&p_libvlc);
718 719 720 721
        if( FAILED(result) )
            return result;

        /* set internal video width and height */
722
        libvlc_video_set_size(p_libvlc,
723 724
            lprcPosRect->right-lprcPosRect->left,
            lprcPosRect->bottom-lprcPosRect->top,
725
            NULL );
726 727

        /* set internal video parent window */
728
        libvlc_video_set_parent(p_libvlc,
729
            reinterpret_cast<libvlc_drawable_t>(_inplacewnd), NULL);
730

731
        if( _b_autoplay & (libvlc_playlist_items_count(p_libvlc, NULL) > 0) )
732
        {
733
            libvlc_playlist_play(p_libvlc, 0, 0, NULL, NULL);
734 735
            fireOnPlayEvent();
        }
736
    }
737 738 739 740

    if( isVisible() )
        ShowWindow(_inplacewnd, SW_SHOW);

741 742 743 744 745
    return S_OK;
};

HRESULT VLCPlugin::onInPlaceDeactivate(void)
{
746 747
    if( isRunning() )
    {
748
        libvlc_playlist_stop(_p_libvlc, NULL);
749 750
        fireOnStopEvent();
    }
751 752 753

    DestroyWindow(_inplacewnd);
    _inplacewnd = NULL;
754

755 756 757 758 759
    return S_OK;
};

void VLCPlugin::setVisible(BOOL fVisible)
{
760 761 762 763 764 765
    if( fVisible != _b_visible )
    {
        _b_visible = fVisible;
        if( isInPlaceActive() )
        {
            ShowWindow(_inplacewnd, fVisible ? SW_SHOW : SW_HIDE);
766
            if( fVisible )
767
                InvalidateRect(_inplacewnd, NULL, TRUE);
768
        }
769
        setDirty(TRUE);
770 771
        firePropChangedEvent(DISPID_Visible);
    }
772 773
};

774 775 776 777 778 779 780 781 782 783 784 785
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() )
        {
786
            libvlc_audio_set_volume(_p_libvlc, _i_volume, NULL);
787 788 789 790 791
        }
        setDirty(TRUE);
    }
};

792 793 794 795 796 797 798 799 800 801 802 803 804
void VLCPlugin::setBackColor(OLE_COLOR backcolor)
{
    if( _i_backcolor != backcolor )
    {
        _i_backcolor = backcolor;
        if( isInPlaceActive() )
        {

        }
        setDirty(TRUE);
    }
};

805 806 807 808 809 810 811
void VLCPlugin::setTime(int seconds)
{
    if( seconds < 0 )
        seconds = 0;

    if( seconds != _i_time )
    {
812
        setStartTime(_i_time);
813 814
        if( isRunning() )
        {
815 816
            libvlc_media_instance_t *p_md = libvlc_playlist_get_media_instance(_p_libvlc, NULL);
            if( NULL != p_md )
817
            {
818
                libvlc_media_instance_set_time(p_md, _i_time, NULL);
819
                libvlc_media_instance_release(p_md);
820
            }
821 822 823 824
        }
    }
};

825 826 827 828 829 830 831 832 833 834 835
void VLCPlugin::setFocus(BOOL fFocus)
{
    if( fFocus )
        SetActiveWindow(_inplacewnd);
};

BOOL VLCPlugin::hasFocus(void)
{
    return GetActiveWindow() == _inplacewnd;
};

Damien Fouilleul's avatar
 
Damien Fouilleul committed
836 837
void VLCPlugin::onDraw(DVTARGETDEVICE * ptd, HDC hicTargetDev,
        HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds)
838
{
839
    if( isVisible() )
840
    {
Damien Fouilleul's avatar
 
Damien Fouilleul committed
841 842 843 844
        long width = lprcBounds->right-lprcBounds->left;
        long height = lprcBounds->bottom-lprcBounds->top;

        RECT bounds = { lprcBounds->left, lprcBounds->top, lprcBounds->right, lprcBounds->bottom };
845

846
        if( isUserMode() )
847
        {
848 849 850 851
            /* VLC is in user mode, just draw background color */
            COLORREF colorref = RGB(0, 0, 0);
            OleTranslateColor(_i_backcolor, (HPALETTE)GetStockObject(DEFAULT_PALETTE), &colorref);
            if( colorref != RGB(0, 0, 0) )
852
            {
853 854 855 856
                /* custom background */
                HBRUSH colorbrush = CreateSolidBrush(colorref);
                FillRect(hdcDraw, &bounds, colorbrush);
                DeleteObject((HANDLE)colorbrush);
857
            }
858
            else
859
            {
860 861
                /* black background */
                FillRect(hdcDraw, &bounds, (HBRUSH)GetStockObject(BLACK_BRUSH));
862
            }
863 864 865 866 867
        }
        else
        {
            /* VLC is in design mode, draw the VLC logo */
            FillRect(hdcDraw, &bounds, (HBRUSH)GetStockObject(WHITE_BRUSH));
868

869 870 871 872 873
            LPPICTURE pict = getPicture();
            if( NULL != pict )
            {
                OLE_XSIZE_HIMETRIC picWidth;
                OLE_YSIZE_HIMETRIC picHeight;
Damien Fouilleul's avatar
 
Damien Fouilleul committed
874

875 876
                pict->get_Width(&picWidth);
                pict->get_Height(&picHeight);
Damien Fouilleul's avatar
 
Damien Fouilleul committed
877

878
                SIZEL picSize = { picWidth, picHeight };
Damien Fouilleul's avatar
 
Damien Fouilleul committed
879

880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896
                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;
897

898 899 900 901 902 903 904 905 906
                if( NULL != lprcWBounds )
                {
                    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);
907

908 909 910 911 912 913 914 915 916 917 918
                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);
        }
Damien Fouilleul's avatar
 
Damien Fouilleul committed
919 920 921 922 923
    }
};

void VLCPlugin::onPaint(HDC hdc, const RECT &bounds, const RECT &clipRect)
{
924
    if( isVisible() )
Damien Fouilleul's avatar
 
Damien Fouilleul committed
925
    {
926
        /* if VLC is in design mode, draw control logo */
927 928
        HDC hdcDraw = CreateCompatibleDC(hdc);
        if( NULL != hdcDraw )
Damien Fouilleul's avatar
 
Damien Fouilleul committed
929
        {
930 931 932 933
            SIZEL size = getExtent();
            DPFromHimetric(hdc, (LPPOINT)&size, 1);
            RECTL posRect = { 0, 0, size.cx, size.cy };

Damien Fouilleul's avatar
 
Damien Fouilleul committed
934 935
            int width = bounds.right-bounds.left;
            int height = bounds.bottom-bounds.top;
936

Damien Fouilleul's avatar
 
Damien Fouilleul committed
937 938 939
            HBITMAP hBitmap = CreateCompatibleBitmap(hdc, width, height);
            if( NULL != hBitmap )
            {
940
                HBITMAP oldBmp = (HBITMAP)SelectObject(hdcDraw, hBitmap);
Damien Fouilleul's avatar
 
Damien Fouilleul committed
941

942
                if( (size.cx != width) || (size.cy != height) )
943 944 945 946 947 948
                {
                    // needs to scale canvas
                    SetMapMode(hdcDraw, MM_ANISOTROPIC);
                    SetWindowExtEx(hdcDraw, size.cx, size.cy, NULL);
                    SetViewportExtEx(hdcDraw, width, height, NULL);
                }
Damien Fouilleul's avatar
 
Damien Fouilleul committed
949

950
                onDraw(NULL, hdc, hdcDraw, &posRect, NULL);
Damien Fouilleul's avatar
 
Damien Fouilleul committed
951

952 953 954 955 956
                SetMapMode(hdcDraw, MM_TEXT);
                BitBlt(hdc, bounds.left, bounds.top,
                        width, height,
                        hdcDraw, 0, 0,
                        SRCCOPY);
Damien Fouilleul's avatar
 
Damien Fouilleul committed
957

958
                SelectObject(hdcDraw, oldBmp);
Damien Fouilleul's avatar
 
Damien Fouilleul committed
959 960
                DeleteObject(hBitmap);
            }
961
            DeleteDC(hdcDraw);
Damien Fouilleul's avatar
 
Damien Fouilleul committed
962
        }
963
    }
964 965 966 967
};

void VLCPlugin::onPositionChange(LPCRECT lprcPosRect, LPCRECT lprcClipRect)
{
Damien Fouilleul's avatar
Damien Fouilleul committed
968 969
    RECT clipRect = *lprcClipRect;

970
    //RedrawWindow(GetParent(_inplacewnd), &_posRect, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN);
971

Damien Fouilleul's avatar
Damien Fouilleul committed
972 973
    /*
    ** record keeping of control geometry within container
974
    */
975
    _posRect = *lprcPosRect;
976 977 978 979

    /*
    ** change in-place window geometry to match clipping region
    */
980
    SetWindowPos(_inplacewnd, NULL,
981 982 983 984
            lprcPosRect->left,
            lprcPosRect->top,
            lprcPosRect->right-lprcPosRect->left,
            lprcPosRect->bottom-lprcPosRect->top,
985 986 987 988
            SWP_NOACTIVATE|
            SWP_NOCOPYBITS|
            SWP_NOZORDER|
            SWP_NOOWNERZORDER );
989

990 991 992
    /* change cliprect coordinates system relative to window bounding rect */
    OffsetRect(&clipRect, -lprcPosRect->left, -lprcPosRect->top);
    HRGN clipRgn = CreateRectRgnIndirect(&clipRect);
993
    SetWindowRgn(_inplacewnd, clipRgn, FALSE);
994

995
    //RedrawWindow(_videownd, &posRect, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN);
996 997 998
    if( isRunning() )
    {
        libvlc_video_set_size(_p_libvlc,
999 1000
            lprcPosRect->right-lprcPosRect->left,
            lprcPosRect->bottom-lprcPosRect->top,
1001 1002
            NULL );
    }
1003 1004
};

Damien Fouilleul's avatar
 
Damien Fouilleul committed
1005 1006 1007 1008 1009
void VLCPlugin::freezeEvents(BOOL freeze)
{
    vlcConnectionPointContainer->freezeEvents(freeze);
};

1010 1011
void VLCPlugin::firePropChangedEvent(DISPID dispid)
{
Damien Fouilleul's avatar
 
Damien Fouilleul committed
1012
    vlcConnectionPointContainer->firePropChangedEvent(dispid); 
1013 1014 1015 1016
};

void VLCPlugin::fireOnPlayEvent(void)
{
Damien Fouilleul's avatar
 
Damien Fouilleul committed
1017 1018
    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
    vlcConnectionPointContainer->fireEvent(DISPID_PlayEvent, &dispparamsNoArgs); 
1019 1020 1021 1022
};

void VLCPlugin::fireOnPauseEvent(void)
{
Damien Fouilleul's avatar
 
Damien Fouilleul committed
1023 1024
    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
    vlcConnectionPointContainer->fireEvent(DISPID_PauseEvent, &dispparamsNoArgs); 
1025 1026 1027 1028
};

void VLCPlugin::fireOnStopEvent(void)
{
Damien Fouilleul's avatar
 
Damien Fouilleul committed
1029 1030
    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
    vlcConnectionPointContainer->fireEvent(DISPID_StopEvent, &dispparamsNoArgs); 
1031
};