plugin.cpp 29.8 KB
Newer Older
1 2 3
/*****************************************************************************
 * plugin.cpp: ActiveX control for VLC
 *****************************************************************************
4
 * Copyright (C) 2005 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 "viewobject.h"
Damien Fouilleul's avatar
 
Damien Fouilleul committed
37
#include "dataobject.h"
38 39 40 41 42

#include "utils.h"

#include <string.h>
#include <winreg.h>
43 44 45 46
#include <winuser.h>
#include <servprov.h>
#include <shlwapi.h>
#include <wininet.h>
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

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<VLCPlugin *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));

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

        case WM_PAINT:
            PAINTSTRUCT ps;
            RECT pr;
            if( GetUpdateRect(hWnd, &pr, FALSE) )
            {
90 91
                RECT bounds;
                GetClientRect(hWnd, &bounds);
92
                BeginPaint(hWnd, &ps);
93
                p_instance->onPaint(ps.hdc, bounds, pr);
94 95 96 97 98 99 100 101 102 103 104
                EndPaint(hWnd, &ps);
            }
            return 0L;

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

VLCPluginClass::VLCPluginClass(LONG *p_class_ref, HINSTANCE hInstance) :
    _p_class_ref(p_class_ref),
Damien Fouilleul's avatar
Damien Fouilleul committed
105 106
    _hinstance(hInstance),
    _inplace_picture(NULL)
107 108 109 110 111
{
    WNDCLASS wClass;

    if( ! GetClassInfo(hInstance, getInPlaceWndClassName(), &wClass) )
    {
112
        wClass.style          = CS_NOCLOSE|CS_DBLCLKS;
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
        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();
       
        _inplace_wndclass_atom = RegisterClass(&wClass);
    }
    else
    {
        _inplace_wndclass_atom = 0;
    }

    if( ! GetClassInfo(hInstance, getVideoWndClassName(), &wClass) )
    {
132
        wClass.style          = CS_NOCLOSE;
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
        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;
    }

Damien Fouilleul's avatar
 
Damien Fouilleul committed
150 151 152 153 154 155 156 157 158
    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;
159

Damien Fouilleul's avatar
 
Damien Fouilleul committed
160 161 162
        if( FAILED(OleCreatePictureIndirect(&pictDesc, IID_IPicture, TRUE, reinterpret_cast<LPVOID*>(&_inplace_picture))) )
            _inplace_picture = NULL;
    }
163 164 165 166 167 168 169 170 171 172 173
    AddRef();
};

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

    if( 0 != _video_wndclass_atom )
        UnregisterClass(MAKEINTATOM(_video_wndclass_atom), _hinstance);

Damien Fouilleul's avatar
 
Damien Fouilleul committed
174 175
    if( NULL != _inplace_picture )
        _inplace_picture->Release();
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
};

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

    if( (IID_IUnknown == riid) || (IID_IClassFactory == riid) )
    {
        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
212
STDMETHODIMP VLCPluginClass::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **ppv)
213 214 215 216 217 218
{
    if( NULL == ppv )
        return E_POINTER;

    *ppv = NULL;

Damien Fouilleul's avatar
 
Damien Fouilleul committed
219
    if( (NULL != pUnkOuter) && (IID_IUnknown != riid) ) {
220
        return CLASS_E_NOAGGREGATION;
Damien Fouilleul's avatar
 
Damien Fouilleul committed
221
    }
222

Damien Fouilleul's avatar
 
Damien Fouilleul committed
223
    VLCPlugin *plugin = new VLCPlugin(this, pUnkOuter);
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
    if( NULL != plugin )
    {
        HRESULT hr = plugin->QueryInterface(riid, ppv);
        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
245
VLCPlugin::VLCPlugin(VLCPluginClass *p_class, LPUNKNOWN pUnkOuter) :
246 247 248
    _inplacewnd(NULL),
    _p_class(p_class),
    _i_ref(1UL),
249 250 251 252 253
    _i_codepage(CP_ACP),
    _b_usermode(TRUE),
    _bstr_mrl(NULL),
    _b_autoplay(TRUE),
    _b_autoloop(FALSE),
254
    _b_visible(TRUE),
255
    _b_mute(FALSE),
256 257 258 259 260 261 262 263 264 265 266 267 268 269
    _i_vlc(0)
{
    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);
270
    vlcViewObject = new VLCViewObject(this);
Damien Fouilleul's avatar
 
Damien Fouilleul committed
271
    vlcDataObject = new VLCDataObject(this);
272
    vlcOleObject = new VLCOleObject(this);
Damien Fouilleul's avatar
 
Damien Fouilleul committed
273 274 275 276 277

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

    // default picure
278
    _p_pict = p_class->getInPlacePict();
Damien Fouilleul's avatar
Damien Fouilleul committed
279 280 281

    // set default/preferred size (320x240) pixels in HIMETRIC
    HDC hDC = CreateDevDC(NULL);
282 283 284
    _extent.cx = 320;
    _extent.cy = 240;
    HimetricFromDP(hDC, (LPPOINT)&_extent, 1);
Damien Fouilleul's avatar
Damien Fouilleul committed
285
    DeleteDC(hDC);
286 287 288 289
};

VLCPlugin::~VLCPlugin()
{
290
    delete vlcOleObject;
Damien Fouilleul's avatar
 
Damien Fouilleul committed
291
    delete vlcDataObject;
292
    delete vlcViewObject;
293 294 295 296 297 298 299 300
    delete vlcControl;
    delete vlcConnectionPointContainer;
    delete vlcProvideClassInfo;
    delete vlcPersistPropertyBag;
    delete vlcPersistStreamInit;
    delete vlcPersistStorage;
    delete vlcOleInPlaceActiveObject;
    delete vlcOleInPlaceObject;
301
    delete vlcObjectSafety;
302

303 304 305
    delete vlcOleControl;
    if( _p_pict )
        _p_pict->Release();
Damien Fouilleul's avatar
 
Damien Fouilleul committed
306

Damien Fouilleul's avatar
Damien Fouilleul committed
307
    SysFreeString(_bstr_mrl);
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329

    _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 )
330
        *ppv = reinterpret_cast<LPVOID>(vlcPersistStreamInit);
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
    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 )
        *ppv = reinterpret_cast<LPVOID>(vlcControl);
    else if( IID_IVLCControl == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcControl);
349 350
    else if( IID_IViewObject == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcViewObject);
Damien Fouilleul's avatar
Damien Fouilleul committed
351 352
    else if( IID_IViewObject2 == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcViewObject);
Damien Fouilleul's avatar
 
Damien Fouilleul committed
353 354 355 356 357 358
    else if( IID_IDataObject == riid )
        *ppv = reinterpret_cast<LPVOID>(vlcDataObject);
    else
    {
        *ppv = NULL;
        return E_NOINTERFACE;
Damien Fouilleul's avatar
Damien Fouilleul committed
359
    }
Damien Fouilleul's avatar
 
Damien Fouilleul committed
360 361
    ((LPUNKNOWN)*ppv)->AddRef();
    return NOERROR;
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
};

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;
};

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

/*
Damien Fouilleul's avatar
Damien Fouilleul committed
382 383 384 385
** we use a window to represent plugin viewport,
** whose geometry is limited by the clipping rectangle
** all drawing within this window must follow must
** follow coordinates system described in lprPosRect
386 387
*/

Damien Fouilleul's avatar
Damien Fouilleul committed
388
static void getViewportCoords(LPRECT lprPosRect, LPRECT lprClipRect)
389
{
Damien Fouilleul's avatar
Damien Fouilleul committed
390 391
    RECT bounds;
    bounds.right  = lprPosRect->right-lprPosRect->left;
392

Damien Fouilleul's avatar
Damien Fouilleul committed
393
    if( lprClipRect->left <= lprPosRect->left )
394 395
    {
        // left side is not clipped out
Damien Fouilleul's avatar
Damien Fouilleul committed
396
        bounds.left = 0;
397

Damien Fouilleul's avatar
Damien Fouilleul committed
398
        if( lprClipRect->right >= lprPosRect->right )
399 400 401
        {
            // right side is not clipped out, no change
        }
Damien Fouilleul's avatar
Damien Fouilleul committed
402
        else if( lprClipRect->right >= lprPosRect->left )
403 404
        {
            // right side is clipped out
Damien Fouilleul's avatar
Damien Fouilleul committed
405
            lprPosRect->right = lprClipRect->right;
406 407 408 409 410 411 412 413 414 415
        }
        else
        {
            // outside of clipping rectange, not visible
            lprPosRect->right = lprPosRect->left;
        }
    }
    else
    {
        // left side is clipped out
Damien Fouilleul's avatar
Damien Fouilleul committed
416 417
        bounds.left = lprPosRect->left-lprClipRect->left;
        bounds.right += bounds.left;
418

Damien Fouilleul's avatar
Damien Fouilleul committed
419 420
        lprPosRect->left = lprClipRect->left;
        if( lprClipRect->right >= lprPosRect->right )
421 422 423 424 425 426
        {
            // right side is not clipped out
        }
        else
        {
            // right side is clipped out
Damien Fouilleul's avatar
Damien Fouilleul committed
427
            lprPosRect->right = lprClipRect->right;
428 429 430
        }
    }

Damien Fouilleul's avatar
Damien Fouilleul committed
431
    bounds.bottom = lprPosRect->bottom-lprPosRect->top;
432

Damien Fouilleul's avatar
Damien Fouilleul committed
433
    if( lprClipRect->top <= lprPosRect->top )
434 435
    {
        // top side is not clipped out
Damien Fouilleul's avatar
Damien Fouilleul committed
436
        bounds.top = 0;
437

Damien Fouilleul's avatar
Damien Fouilleul committed
438
        if( lprClipRect->bottom >= lprPosRect->bottom )
439 440 441
        {
            // bottom side is not clipped out, no change
        }
Damien Fouilleul's avatar
Damien Fouilleul committed
442
        else if( lprClipRect->bottom >= lprPosRect->top )
443 444
        {
            // bottom side is clipped out
Damien Fouilleul's avatar
Damien Fouilleul committed
445
            lprPosRect->bottom = lprClipRect->bottom;
446 447 448 449 450 451 452 453 454
        }
        else
        {
            // outside of clipping rectange, not visible
            lprPosRect->right = lprPosRect->left;
        }
    }
    else
    {
Damien Fouilleul's avatar
Damien Fouilleul committed
455 456
        bounds.top = lprPosRect->top-lprClipRect->top;
        bounds.bottom += bounds.top;
457

Damien Fouilleul's avatar
Damien Fouilleul committed
458 459
        lprPosRect->top = lprClipRect->top;
        if( lprClipRect->bottom >= lprPosRect->bottom )
460 461 462 463 464 465
        {
            // bottom side is not clipped out
        }
        else
        {
            // bottom side is clipped out
Damien Fouilleul's avatar
Damien Fouilleul committed
466
            lprPosRect->bottom = lprClipRect->bottom;
467 468
        }
    }
Damien Fouilleul's avatar
Damien Fouilleul committed
469 470
    *lprClipRect = *lprPosRect;
    *lprPosRect  = bounds;
471 472
};

473
HRESULT VLCPlugin::onInit(void)
474 475 476
{
    if( 0 == _i_vlc )
    {
477 478 479 480 481 482 483 484 485 486 487 488 489
        _i_vlc = VLC_Create();
        if( _i_vlc < 0 )
        {
            _i_vlc = 0;
            return E_FAIL;
        }

        /*
        ** default initialization options
        */
        char *ppsz_argv[10] = { "vlc", "-vv" };
        int   ppsz_argc = 2;

490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
        HKEY h_key;
        DWORD i_type, i_data = MAX_PATH + 1;
        char p_data[MAX_PATH + 1];
        if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\VideoLAN\\VLC",
                          0, KEY_READ, &h_key ) == ERROR_SUCCESS )
        {
             if( RegQueryValueEx( h_key, "InstallDir", 0, &i_type,
                                  (LPBYTE)p_data, &i_data ) == ERROR_SUCCESS )
             {
                 if( i_type == REG_SZ )
                 {
                     strcat( p_data, "\\vlc" );
                     ppsz_argv[0] = p_data;
                 }
             }
             RegCloseKey( h_key );
        }

508
#if 0
509 510 511
        ppsz_argv[0] = "C:\\cygwin\\home\\Damien_Fouilleul\\dev\\videolan\\vlc-trunk\\vlc";
#endif

512
        if( IsDebuggerPresent() )
Damien Fouilleul's avatar
Damien Fouilleul committed
513
        {
514 515 516 517 518 519 520 521 522 523
            /*
            ** 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
            */
            ppsz_argv[ppsz_argc++] = "--fast-mutex";
            ppsz_argv[ppsz_argc++] = "--win9x-cv-method=1";
Damien Fouilleul's avatar
Damien Fouilleul committed
524
        }
525

526
        if( VLC_Init(_i_vlc, ppsz_argc, ppsz_argv) )
527 528 529 530 531 532 533
        {
            VLC_Destroy(_i_vlc);
            _i_vlc = 0;
            return E_FAIL;
        }
        return S_OK;
    }
Damien Fouilleul's avatar
 
Damien Fouilleul committed
534
    return CO_E_ALREADYINITIALIZED;
535
};
536 537 538

HRESULT VLCPlugin::onLoad(void)
{
539 540
    if( _b_mute )
        VLC_VolumeMute(_i_vlc);
541

Damien Fouilleul's avatar
Damien Fouilleul committed
542
    if( SysStringLen(_bstr_mrl) > 0 )
543
    {
544 545 546 547 548 549
        /*
        ** try to combine MRL with client site moniker, which for Internet Explorer
        ** is the URL of the page the plugin is embedded into. Hence, if the MRL
        ** is a relative URL, we should end up with an absolute URL
        */
        IOleClientSite *pClientSite;
Damien Fouilleul's avatar
Damien Fouilleul committed
550
        if( SUCCEEDED(vlcOleObject->GetClientSite(&pClientSite)) && (NULL != pClientSite) )
551 552 553 554 555 556 557 558
        {
            IBindCtx *pBC = 0;
            if( SUCCEEDED(CreateBindCtx(0, &pBC)) )
            {
                LPMONIKER pContMoniker = NULL;
                if( SUCCEEDED(pClientSite->GetMoniker(OLEGETMONIKER_ONLYIFTHERE,
                                OLEWHICHMK_CONTAINER, &pContMoniker)) )
                {
559 560
                    LPOLESTR base_url;
                    if( SUCCEEDED(pContMoniker->GetDisplayName(pBC, NULL, &base_url)) )
561
                    {
562 563 564
                        /*
                        ** check that the moniker name is a URL
                        */
565
                        if( UrlIsW(base_url, URLIS_URL) )
566
                        {
567
                            DWORD len = INTERNET_MAX_URL_LENGTH;
568 569
                            LPOLESTR abs_url = (LPOLESTR)CoTaskMemAlloc(sizeof(OLECHAR)*len);
                            if( NULL != abs_url )
570
                            {
571
                                if( SUCCEEDED(UrlCombineW(base_url, _bstr_mrl, abs_url, &len,
572
                                                URL_ESCAPE_UNSAFE|URL_PLUGGABLE_PROTOCOL)) )
573 574
                                {
                                    SysFreeString(_bstr_mrl);
575
                                    _bstr_mrl = SysAllocStringLen(abs_url, len);
576
                                }
577
                                CoTaskMemFree(abs_url);
578 579
                            }
                        }
580
                        CoTaskMemFree(base_url);
581 582 583 584 585 586 587
                    }
                    pContMoniker->Release();
                }
                pBC->Release();
            }
            pClientSite->Release();
        }
588

589 590
        char *psz_mrl = CStrFromBSTR(CP_UTF8, _bstr_mrl);
        if( NULL != psz_mrl )
591
        {
592 593 594 595 596 597 598 599 600 601
            // add default target to playlist
            char *cOptions[1];
            int  cOptionsCount = 0;

            if( _b_autoloop )
            {
                cOptions[cOptionsCount++] = "loop";
            }
            VLC_AddTarget(_i_vlc, psz_mrl, (const char **)&cOptions, cOptionsCount, PLAYLIST_APPEND, PLAYLIST_END);
            CoTaskMemFree(psz_mrl);
602
        }
603
    }
604
    setDirty(FALSE);
605 606 607
    return S_OK;
};

608
HRESULT VLCPlugin::onAmbientChanged(LPUNKNOWN pContainer, DISPID dispID)
609
{
610 611
    VARIANT v;
    switch( dispID )
612
    {
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
        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:
668 669 670
        /*
        ** multiple property change, look up the ones we are interested in
        */
671 672 673 674 675 676 677 678
            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;
679
            if( SUCCEEDED(GetObjectProperty(pContainer, DISPID_AMBIENT_CODEPAGE, v)) )
680 681 682 683
            {
                setCodePage(V_I4(&v));
            }
            break;
684 685 686 687
    }
    return S_OK;
};

688 689 690 691
HRESULT VLCPlugin::onClose(DWORD dwSaveOption)
{
    if( _i_vlc )
    {
Damien Fouilleul's avatar
 
Damien Fouilleul committed
692 693 694
        int i_vlc = _i_vlc;

        _i_vlc = 0;
695 696 697 698
        if( isInPlaceActive() )
        {
            onInPlaceDeactivate();
        }
Damien Fouilleul's avatar
 
Damien Fouilleul committed
699
        vlcDataObject->onClose();
700

Damien Fouilleul's avatar
 
Damien Fouilleul committed
701 702
        VLC_CleanUp(i_vlc);
        VLC_Destroy(i_vlc);
703 704 705 706 707 708 709 710 711 712 713 714
    }
    return S_OK;
};

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

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

Damien Fouilleul's avatar
Damien Fouilleul committed
717 718 719 720 721 722 723 724 725
    /*
    ** record keeping of control geometry within container
    */ 
    _posRect = posRect;

    /*
    ** convert posRect & clipRect to match control viewport coordinates
    */
    getViewportCoords(&posRect, &clipRect);
726

Damien Fouilleul's avatar
Damien Fouilleul committed
727 728
    /*
    ** Create a window for in place activated control.
729 730 731
    ** the window geometry matches the control viewport
    ** within container so that embedded video is always
    ** properly clipped.
Damien Fouilleul's avatar
Damien Fouilleul committed
732
    */
733 734
    _inplacewnd = CreateWindow(_p_class->getInPlaceWndClassName(),
            "VLC Plugin In-Place Window",
735
            WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,
Damien Fouilleul's avatar
Damien Fouilleul committed
736 737 738 739
            clipRect.left,
            clipRect.top,
            clipRect.right-clipRect.left,
            clipRect.bottom-clipRect.top,
740 741 742 743 744 745 746 747 748 749 750
            hwndParent,
            0,
            _p_class->getHInstance(),
            NULL
           );

    if( NULL == _inplacewnd )
        return E_FAIL;

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

Damien Fouilleul's avatar
Damien Fouilleul committed
751
    /*
752 753 754
    ** VLC embedded video automatically grows to cover client
    ** area of parent window.
    ** hence create a such a 'parent' window whose geometry
Damien Fouilleul's avatar
Damien Fouilleul committed
755 756
    ** is always correct relative to the viewport bounds
    */
757 758 759
    _videownd = CreateWindow(_p_class->getVideoWndClassName(),
            "VLC Plugin Video Window",
            WS_CHILD|WS_CLIPCHILDREN|WS_VISIBLE,
Damien Fouilleul's avatar
Damien Fouilleul committed
760 761 762 763
            posRect.left,
            posRect.top,
            posRect.right-posRect.left,
            posRect.bottom-posRect.top,
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
            _inplacewnd,
            0,
            _p_class->getHInstance(),
            NULL
           );

    if( NULL == _videownd )
    {
        DestroyWindow(_inplacewnd);
        return E_FAIL;
    }

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

    if( getVisible() )
        ShowWindow(_inplacewnd, SW_SHOWNORMAL);

781
    /* set internal video width and height */
782
    vlc_value_t val;
783
    val.i_int = posRect.right-posRect.left;
784
    VLC_VariableSet(_i_vlc, "conf::width", val);
785
    val.i_int = posRect.bottom-posRect.top;
786
    VLC_VariableSet(_i_vlc, "conf::height", val);
787

788 789 790 791 792
    /* set internal video parent window */
    /* horrible cast there */
    val.i_int = reinterpret_cast<int>(_videownd);
    VLC_VariableSet(_i_vlc, "drawable", val);

793
    if( _b_usermode && _b_autoplay & (VLC_PlaylistNumberOfItems(_i_vlc) > 0) )
794
    {
795 796
        VLC_Play(_i_vlc);
        fireOnPlayEvent();
797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
    }
    return S_OK;
};

HRESULT VLCPlugin::onInPlaceDeactivate(void)
{
    VLC_Stop(_i_vlc);
    fireOnStopEvent();

    DestroyWindow(_videownd);
    _videownd = NULL;
    DestroyWindow(_inplacewnd);
    _inplacewnd = NULL;
 
    return S_OK;
};

void VLCPlugin::setVisible(BOOL fVisible)
{
    _b_visible = fVisible;
    if( isInPlaceActive() )
        ShowWindow(_inplacewnd, fVisible ? SW_SHOWNORMAL : SW_HIDE);
    firePropChangedEvent(DISPID_Visible);
};

void VLCPlugin::setFocus(BOOL fFocus)
{
    if( fFocus )
        SetActiveWindow(_inplacewnd);
};

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

Damien Fouilleul's avatar
 
Damien Fouilleul committed
833 834
void VLCPlugin::onDraw(DVTARGETDEVICE * ptd, HDC hicTargetDev,
        HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds)
835
{
836
    if( getVisible() )
837
    {
Damien Fouilleul's avatar
 
Damien Fouilleul committed
838 839 840 841 842
        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));
843

Damien Fouilleul's avatar
 
Damien Fouilleul committed
844
        LPPICTURE pict = getPicture();
845
        if( NULL != pict )
846
        {
Damien Fouilleul's avatar
 
Damien Fouilleul committed
847 848 849 850 851 852
            OLE_XSIZE_HIMETRIC picWidth;
            OLE_YSIZE_HIMETRIC picHeight;

            pict->get_Width(&picWidth);
            pict->get_Height(&picHeight);

853
            SIZEL picSize = { picWidth, picHeight };
Damien Fouilleul's avatar
 
Damien Fouilleul committed
854

855 856 857 858 859 860 861 862 863 864 865 866 867 868
            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;
Damien Fouilleul's avatar
 
Damien Fouilleul committed
869

870 871
            LONG dstX = lprcBounds->left+(width-picSize.cx)/2;
            LONG dstY = lprcBounds->top+(height-picSize.cy)/2;
Damien Fouilleul's avatar
 
Damien Fouilleul committed
872 873

            if( NULL != lprcWBounds )
874
            {
Damien Fouilleul's avatar
 
Damien Fouilleul committed
875
                RECT wBounds = { lprcWBounds->left, lprcWBounds->top, lprcWBounds->right, lprcWBounds->bottom };
876
                pict->Render(hdcDraw, dstX, dstY, picSize.cx, picSize.cy,
Damien Fouilleul's avatar
 
Damien Fouilleul committed
877
                        0L, picHeight, picWidth, -picHeight, &wBounds);
878
            }
Damien Fouilleul's avatar
 
Damien Fouilleul committed
879
            else 
880
                pict->Render(hdcDraw, dstX, dstY, picSize.cx, picSize.cy,
Damien Fouilleul's avatar
 
Damien Fouilleul committed
881 882 883
                        0L, picHeight, picWidth, -picHeight, NULL);

            pict->Release();
884 885
        }

Damien Fouilleul's avatar
 
Damien Fouilleul committed
886
        SelectObject(hdcDraw, GetStockObject(BLACK_BRUSH));
887

Damien Fouilleul's avatar
 
Damien Fouilleul committed
888 889 890 891 892 893 894 895 896 897 898 899 900 901
        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);
    }
};

void VLCPlugin::onPaint(HDC hdc, const RECT &bounds, const RECT &clipRect)
{
    if( getVisible() )
    {
        /** if VLC is playing, it may not display any VIDEO content 
        ** hence, draw control logo*/
902 903
        HDC hdcDraw = CreateCompatibleDC(hdc);
        if( NULL != hdcDraw )
Damien Fouilleul's avatar
 
Damien Fouilleul committed
904
        {
905 906 907 908
            SIZEL size = getExtent();
            DPFromHimetric(hdc, (LPPOINT)&size, 1);
            RECTL posRect = { 0, 0, size.cx, size.cy };

Damien Fouilleul's avatar
 
Damien Fouilleul committed
909 910
            int width = bounds.right-bounds.left;
            int height = bounds.bottom-bounds.top;
911

Damien Fouilleul's avatar
 
Damien Fouilleul committed
912 913 914
            HBITMAP hBitmap = CreateCompatibleBitmap(hdc, width, height);
            if( NULL != hBitmap )
            {
915
                HBITMAP oldBmp = (HBITMAP)SelectObject(hdcDraw, hBitmap);
Damien Fouilleul's avatar
 
Damien Fouilleul committed
916

917
                if( (size.cx != width) || (size.cy != height) )
918 919 920 921 922 923
                {
                    // 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
924

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

927 928 929 930 931
                SetMapMode(hdcDraw, MM_TEXT);
                BitBlt(hdc, bounds.left, bounds.top,
                        width, height,
                        hdcDraw, 0, 0,
                        SRCCOPY);
Damien Fouilleul's avatar
 
Damien Fouilleul committed
932

933
                SelectObject(hdcDraw, oldBmp);
Damien Fouilleul's avatar
 
Damien Fouilleul committed
934 935
                DeleteObject(hBitmap);
            }
936
            DeleteDC(hdcDraw);
Damien Fouilleul's avatar
 
Damien Fouilleul committed
937
        }
938
    }
939 940 941 942
};

void VLCPlugin::onPositionChange(LPCRECT lprcPosRect, LPCRECT lprcClipRect)
{
Damien Fouilleul's avatar
Damien Fouilleul committed
943 944 945
    RECT clipRect = *lprcClipRect;
    RECT posRect  = *lprcPosRect;

946
    //RedrawWindow(GetParent(_inplacewnd), &_posRect, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN);
947

Damien Fouilleul's avatar
Damien Fouilleul committed
948 949
    /*
    ** record keeping of control geometry within container
950
    */
Damien Fouilleul's avatar
Damien Fouilleul committed
951
    _posRect = posRect;
952

Damien Fouilleul's avatar
Damien Fouilleul committed
953 954 955 956
    /*
    ** convert posRect & clipRect to match control viewport coordinates
    */
    getViewportCoords(&posRect, &clipRect);
957 958 959 960

    /*
    ** change in-place window geometry to match clipping region
    */
961
    SetWindowPos(_inplacewnd, NULL,
Damien Fouilleul's avatar
Damien Fouilleul committed
962 963 964 965
            clipRect.left,
            clipRect.top,
            clipRect.right-clipRect.left,
            clipRect.bottom-clipRect.top,
966 967 968 969
            SWP_NOACTIVATE|
            SWP_NOCOPYBITS|
            SWP_NOZORDER|
            SWP_NOOWNERZORDER );
970 971 972 973

    /*
    ** change video window geometry to match object bounds within clipping region
    */
974
    SetWindowPos(_videownd, NULL,
Damien Fouilleul's avatar
Damien Fouilleul committed
975 976 977 978
            posRect.left,
            posRect.top,
            posRect.right-posRect.left,
            posRect.bottom-posRect.top,
979 980 981 982
            SWP_NOACTIVATE|
            SWP_NOCOPYBITS|
            SWP_NOZORDER|
            SWP_NOOWNERZORDER );
983

984 985 986
    //RedrawWindow(_videownd, &posRect, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN);
    vlc_value_t val;
    val.i_int = posRect.right-posRect.left;
987
    VLC_VariableSet(_i_vlc, "conf::width", val);
988
    val.i_int = posRect.bottom-posRect.top;
989
    VLC_VariableSet(_i_vlc, "conf::height", val);
990 991
};

Damien Fouilleul's avatar
 
Damien Fouilleul committed
992 993 994 995 996
void VLCPlugin::freezeEvents(BOOL freeze)
{
    vlcConnectionPointContainer->freezeEvents(freeze);
};

997 998
void VLCPlugin::firePropChangedEvent(DISPID dispid)
{
Damien Fouilleul's avatar
 
Damien Fouilleul committed
999
    vlcConnectionPointContainer->firePropChangedEvent(dispid); 
1000 1001 1002 1003
};

void VLCPlugin::fireOnPlayEvent(void)
{
Damien Fouilleul's avatar
 
Damien Fouilleul committed
1004 1005
    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
    vlcConnectionPointContainer->fireEvent(DISPID_PlayEvent, &dispparamsNoArgs); 
1006 1007 1008 1009
};

void VLCPlugin::fireOnPauseEvent(void)
{
Damien Fouilleul's avatar
 
Damien Fouilleul committed
1010 1011
    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
    vlcConnectionPointContainer->fireEvent(DISPID_PauseEvent, &dispparamsNoArgs); 
1012 1013 1014 1015
};

void VLCPlugin::fireOnStopEvent(void)
{
Damien Fouilleul's avatar
 
Damien Fouilleul committed
1016 1017
    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
    vlcConnectionPointContainer->fireEvent(DISPID_StopEvent, &dispparamsNoArgs); 
1018 1019
};