Files
libreoffice/extensions/source/activex/SOActiveX.cxx
Mike Kaganski 362a21d3a1 Use explicit function names for fooA/fooW WinAPI; prefer fooW
We should only use generic foo function name when it takes params
that are also dependent on UNICODE define, like
LoadCursor( nullptr, IDC_ARROW )
where IDC_ARROW is defined in MSVC headers synchronised with
LoadCursor definition.

We should always use Unicode API for any file paths operations,
because otherwise we will get "?" for any character in path that
is not in current non-unicode codepage, which will result in failed
file operations.

Change-Id: I3a7f453ca0f893002d8a9764318919709fd8b633
Reviewed-on: https://gerrit.libreoffice.org/42935
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
2017-09-30 11:23:41 +02:00

1172 lines
40 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// SOActiveX.cpp : Implementation of CSOActiveX
#pragma warning (push,1)
#pragma warning (disable:4265)
#include "StdAfx2.h"
#include "SOActiveX.h"
#include "SOComWindowPeer.h"
#include "SODispatchInterceptor.h"
#include "SOActionsApproval.h"
#if defined __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
#endif
#include "so_activex.h"
#if defined __clang__
#pragma clang diagnostic pop
#endif
#pragma warning (pop)
#define STAROFFICE_WINDOWCLASS L"SOParentWindow"
void OutputError_Impl( HWND hw, HRESULT ErrorCode )
{
LPWSTR sMessage;
FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
nullptr,
ErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
reinterpret_cast<LPWSTR>(&sMessage),
0,
nullptr
);
MessageBoxW( hw, sMessage, nullptr, MB_OK | MB_ICONINFORMATION );
LocalFree( sMessage );
}
HRESULT ExecuteFunc( IDispatch* idispUnoObject,
OLECHAR const * sFuncName,
CComVariant* params,
unsigned int count,
CComVariant* pResult )
{
if( !idispUnoObject )
return E_FAIL;
DISPID id;
HRESULT hr = idispUnoObject->GetIDsOfNames( IID_NULL, const_cast<OLECHAR **>(&sFuncName), 1, LOCALE_USER_DEFAULT, &id);
if( !SUCCEEDED( hr ) ) return hr;
DISPPARAMS dispparams= { params, nullptr, count, 0};
// DEBUG
EXCEPINFO myInfo;
hr = idispUnoObject->Invoke( id, IID_NULL,LOCALE_USER_DEFAULT, DISPATCH_METHOD,
&dispparams, pResult, &myInfo, nullptr);
// for debugging purposes
// USES_CONVERSION;
// if ( !SUCCEEDED( hr ) )
// ::MessageBox( NULL, OLE2A( myInfo.bstrDescription ), OLE2A( myInfo.bstrSource ), MB_OK | MB_ICONINFORMATION );
return hr;
}
HRESULT GetIDispByFunc( IDispatch* idispUnoObject,
OLECHAR const * sFuncName,
CComVariant* params,
unsigned int count,
CComPtr<IDispatch>& pdispResult )
{
if( !idispUnoObject )
return E_FAIL;
CComVariant result;
HRESULT hr = ExecuteFunc( idispUnoObject, sFuncName, params, count, &result );
if( !SUCCEEDED( hr ) ) return hr;
if( result.vt != VT_DISPATCH || result.pdispVal == nullptr )
return E_FAIL;
pdispResult = CComPtr<IDispatch>( result.pdispVal );
return S_OK;
}
HRESULT PutPropertiesToIDisp( IDispatch* pdispObject,
OLECHAR const ** sMemberNames,
CComVariant* pVariant,
unsigned int count )
{
for( unsigned int ind = 0; ind < count; ind++ )
{
DISPID id;
HRESULT hr = pdispObject->GetIDsOfNames( IID_NULL, const_cast<OLECHAR **>(&sMemberNames[ind]), 1, LOCALE_USER_DEFAULT, &id );
if( !SUCCEEDED( hr ) ) return hr;
hr = CComDispatchDriver::PutProperty( pdispObject, id, &pVariant[ind] );
if( !SUCCEEDED( hr ) ) return hr;
}
return S_OK;
}
HRESULT GetPropertiesFromIDisp( IDispatch* pdispObject,
OLECHAR const ** sMemberNames,
CComVariant* pVariant,
unsigned int count )
{
for( unsigned int ind = 0; ind < count; ind++ )
{
DISPID id;
HRESULT hr = pdispObject->GetIDsOfNames( IID_NULL, const_cast<OLECHAR **>(&sMemberNames[ind]), 1, LOCALE_USER_DEFAULT, &id );
if( !SUCCEEDED( hr ) ) return hr;
hr = CComDispatchDriver::GetProperty( pdispObject, id, &pVariant[ind] );
if( !SUCCEEDED( hr ) ) return hr;
}
return S_OK;
}
// CSOActiveX
CSOActiveX::CSOActiveX()
: mCookie(0)
, mCurFileUrl( L"private:factory/swriter" )
, mbLoad( FALSE )
, mbViewOnly( TRUE )
, mParentWin( nullptr )
, mOffWin( nullptr )
, mpDispatchInterceptor( nullptr )
, mnVersion( SO_NOT_DETECTED )
, mbReadyForActivation( FALSE )
, mbDrawLocked( FALSE )
{
CLSID const clsFactory = {0x82154420,0x0FBF,0x11d4,{0x83, 0x13,0x00,0x50,0x04,0x52,0x6A,0xB4}};
HRESULT hr = CoCreateInstance( clsFactory, nullptr, CLSCTX_ALL, __uuidof(IDispatch), reinterpret_cast<void**>(&mpDispFactory));
if( !SUCCEEDED( hr ) )
OutputError_Impl( nullptr, hr );
mPWinClass.style = CS_HREDRAW|CS_VREDRAW;
mPWinClass.lpfnWndProc = DefWindowProcW;
mPWinClass.cbClsExtra = 0;
mPWinClass.cbWndExtra = 0;
mPWinClass.hInstance = GetModuleHandleW(nullptr); //myInstance;
mPWinClass.hIcon = nullptr;
mPWinClass.hCursor = nullptr;
mPWinClass.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BACKGROUND);
mPWinClass.lpszMenuName = nullptr;
mPWinClass.lpszClassName = STAROFFICE_WINDOWCLASS;
RegisterClassW(&mPWinClass);
}
CSOActiveX::~CSOActiveX()
{
Cleanup();
}
HRESULT CSOActiveX::Cleanup()
{
CComVariant dummyResult;
if( mpDispatchInterceptor )
{
if( mpDispFrame )
{
// remove dispatch interceptor
CComQIPtr< IDispatch, &IID_IDispatch > pIDispDispInter( mpDispatchInterceptor );
CComVariant aVariant( pIDispDispInter );
ExecuteFunc( mpDispFrame,
L"releaseDispatchProviderInterceptor",
&aVariant,
1,
&dummyResult );
}
mpDispatchInterceptor->ClearParent();
mpDispatchInterceptor->Release();
mpDispatchInterceptor = nullptr;
}
mpDispTempFile = CComPtr< IDispatch >();
mbReadyForActivation = FALSE;
if( mpInstanceLocker )
{
ExecuteFunc( mpInstanceLocker, L"dispose", nullptr, 0, &dummyResult );
mpInstanceLocker = CComPtr< IDispatch >();
}
if( mpDispFrame )
{
BOOL bCloserActivated = FALSE;
CComPtr<IDispatch> pDispDocumentCloser;
CComVariant aDocCloser( L"com.sun.star.embed.DocumentCloser" );
HRESULT hr = GetIDispByFunc( mpDispFactory,
L"createInstance",
&aDocCloser,
1,
pDispDocumentCloser );
if ( SUCCEEDED( hr ) && pDispDocumentCloser )
{
SAFEARRAY FAR* pInitFrame = SafeArrayCreateVector( VT_VARIANT, 0, 1 );
long nInitInd = 0;
CComVariant pFrameVariant( mpDispFrame );
SafeArrayPutElement( pInitFrame, &nInitInd, &pFrameVariant );
CComVariant aVarInitFrame;
aVarInitFrame.vt = VT_ARRAY | VT_VARIANT; aVarInitFrame.parray = pInitFrame;
hr = ExecuteFunc( pDispDocumentCloser, L"initialize", &aVarInitFrame, 1, &dummyResult );
if( SUCCEEDED( hr ) )
{
// the following call will let the closing happen
hr = ExecuteFunc( pDispDocumentCloser, L"dispose", nullptr, 0, &dummyResult );
bCloserActivated = SUCCEEDED( hr );
}
}
if ( !bCloserActivated )
{
CComVariant aPropVar;
aPropVar.vt = VT_BOOL; aPropVar.boolVal = VARIANT_TRUE;
if ( !SUCCEEDED( ExecuteFunc( mpDispFrame, L"close", &aPropVar, 1, &dummyResult ) ) )
ExecuteFunc( mpDispFrame, L"dispose", nullptr, 0, &dummyResult );
}
mpDispFrame = CComPtr< IDispatch >();
}
if( ::IsWindow( mOffWin ) )
::DestroyWindow( mOffWin );
TerminateOffice();
return S_OK;
}
HRESULT CSOActiveX::TerminateOffice()
{
// create desktop
CComPtr<IDispatch> pdispDesktop;
CComVariant aDesktopServiceName( L"com.sun.star.frame.Desktop" );
HRESULT hr = GetIDispByFunc( mpDispFactory, L"createInstance", &aDesktopServiceName, 1, pdispDesktop );
if( !pdispDesktop || !SUCCEEDED( hr ) ) return hr;
// create tree of frames
CComPtr<IDispatch> pdispChildren;
hr = GetIDispByFunc( pdispDesktop, L"getFrames", nullptr, 0, pdispChildren );
if( !pdispChildren || !SUCCEEDED( hr ) ) return hr;
CComVariant aFrames;
CComVariant nFlag( 4 );
hr = ExecuteFunc( pdispChildren, L"queryFrames", &nFlag, 1, &aFrames );
if ( SUCCEEDED( hr ) )
{
if ( ( aFrames.vt == ( VT_ARRAY | VT_DISPATCH ) || aFrames.vt == ( VT_ARRAY | VT_VARIANT ) )
&& ( !aFrames.parray || (aFrames.parray->cDims == 1 && aFrames.parray->rgsabound[0].cElements == 0) ) )
{
// there is no frames open
// TODO: check whether the frames are hidden if they are open?
CComVariant dummyResult;
hr = ExecuteFunc( pdispDesktop, L"terminate", nullptr, 0, &dummyResult );
}
}
return hr;
}
STDMETHODIMP CSOActiveX::InitNew ()
{
mnVersion = GetVersionConnected();
mbLoad = TRUE;
return S_OK;
}
STDMETHODIMP CSOActiveX::Load ( LPSTREAM /*pStm*/ )
{
mnVersion = GetVersionConnected();
mbLoad = TRUE;
// may be later?
// for now just ignore
return S_OK;
}
STDMETHODIMP CSOActiveX::Load( LPPROPERTYBAG pPropBag, LPERRORLOG /*pErrorLog*/ )
{
mnVersion = GetVersionConnected();
IPropertyBag2* pPropBag2;
HRESULT hr = pPropBag->QueryInterface( IID_IPropertyBag2, reinterpret_cast<void**>(&pPropBag2) );
//ATLASSERT( hr >= 0 );
if( !SUCCEEDED( hr ) )
return hr;
unsigned long aNum;
hr = pPropBag2->CountProperties( &aNum );
//ATLASSERT( hr >= 0 );
if( !SUCCEEDED( hr ) )
return hr;
PROPBAG2* aPropNames = new PROPBAG2[aNum];
unsigned long aReaded;
hr = pPropBag2->GetPropertyInfo( 0,
aNum,
aPropNames,
&aReaded );
//ATLASSERT( hr >= 0 );
if( !SUCCEEDED( hr ) )
{
delete[] aPropNames;
return hr;
}
CComVariant* aVal = new CComVariant[aNum];
HRESULT* hvs = new HRESULT[aNum];
hr = pPropBag2->Read( aNum,
aPropNames,
nullptr,
aVal,
hvs );
//ATLASSERT( hr >= 0 );
if( !SUCCEEDED( hr ) )
{
delete[] hvs;
delete[] aVal;
delete[] aPropNames;
return hr;
}
USES_CONVERSION;
for( unsigned long ind = 0; ind < aNum; ind++ )
{
// all information from the 'object' tag is in strings
if( aVal[ind].vt == VT_BSTR && !strcmp( OLE2T( aPropNames[ind].pstrName ), "src" ) )
{
mCurFileUrl = wcsdup( aVal[ind].bstrVal );
}
else if( aVal[ind].vt == VT_BSTR
&& !strcmp( OLE2T( aPropNames[ind].pstrName ), "readonly" ) )
{
if( !strcmp( OLE2T( aVal[ind].bstrVal ), "true" ) )
{
// the default value
mbViewOnly = TRUE;
}
else
{
mbViewOnly = FALSE;
}
}
}
delete[] hvs;
delete[] aVal;
delete[] aPropNames;
if( !mpDispFactory )
return hr;
mbReadyForActivation = FALSE;
hr = CBindStatusCallback<CSOActiveX>::Download( this, &CSOActiveX::CallbackCreateXInputStream, const_cast<OLECHAR *>(mCurFileUrl), m_spClientSite, FALSE );
if ( hr == MK_S_ASYNCHRONOUS )
hr = S_OK;
if ( !SUCCEEDED( hr ) )
{
// trigger initialization without stream
mbLoad = TRUE;
Invalidate();
UpdateWindow();
}
return hr;
}
HRESULT CSOActiveX::GetUnoStruct( OLECHAR const * sStructName, CComPtr<IDispatch>& pdispResult )
{
CComVariant aComStruct( sStructName );
return GetIDispByFunc( mpDispFactory, L"Bridge_GetStruct", &aComStruct, 1, pdispResult );
}
HRESULT CSOActiveX::GetUrlStruct( OLECHAR const * sUrl, CComPtr<IDispatch>& pdispUrl )
{
HRESULT hr = GetUnoStruct( L"com.sun.star.util.URL", pdispUrl );
if( !SUCCEEDED( hr ) ) return hr;
OLECHAR const * sURLMemberName = L"Complete";
DISPID nURLID;
hr = pdispUrl->GetIDsOfNames( IID_NULL, const_cast<OLECHAR **>(&sURLMemberName), 1, LOCALE_USER_DEFAULT, &nURLID );
if( !SUCCEEDED( hr ) ) return hr;
CComVariant aComUrl( sUrl );
hr = CComDispatchDriver::PutProperty( pdispUrl, nURLID, &aComUrl );
if( !SUCCEEDED( hr ) ) return hr;
CComPtr<IDispatch> pdispTransformer;
CComVariant aServiceName( L"com.sun.star.util.URLTransformer" );
hr = GetIDispByFunc( mpDispFactory,
L"createInstance",
&aServiceName,
1,
pdispTransformer );
if( !SUCCEEDED( hr ) ) return hr;
CComVariant dummyResult;
CComVariant aParam[2];
aParam[1].ppdispVal = &pdispUrl;
aParam[1].vt = VT_DISPATCH | VT_BYREF;
aParam[0] = CComVariant( L"file:///" );
hr = ExecuteFunc( pdispTransformer, L"parseSmart", aParam, 2, &dummyResult );
if( !SUCCEEDED( hr ) || dummyResult.vt != VT_BOOL || !dummyResult.boolVal ) return hr;
return S_OK;
}
HRESULT CSOActiveX::SetLayoutManagerProps()
{
if ( !mpDispFrame )
return E_FAIL;
CComVariant pVarLayoutMgr;
OLECHAR const * sLMPropName = L"LayoutManager";
HRESULT hr = GetPropertiesFromIDisp( mpDispFrame, &sLMPropName, &pVarLayoutMgr, 1 );
if( pVarLayoutMgr.vt != VT_DISPATCH || pVarLayoutMgr.pdispVal == nullptr )
return E_FAIL;
CComPtr<IDispatch> pdispLM( pVarLayoutMgr.pdispVal );
if( !SUCCEEDED( hr ) || !pdispLM )
return E_FAIL;
OLECHAR const * sATName = L"AutomaticToolbars";
CComVariant pATProp;
pATProp.vt = VT_BOOL; pATProp.boolVal = VARIANT_FALSE ;
hr = PutPropertiesToIDisp( pdispLM, &sATName, &pATProp, 1 );
return hr;
}
HRESULT CSOActiveX::CreateFrameOldWay( HWND hwnd, int width, int height )
{
if( !mpDispFactory )
return E_FAIL;
// create window handle holder
CComPtr< CComObject< SOComWindowPeer > > pPeerToSend = new CComObject<SOComWindowPeer>();
pPeerToSend->SetHWNDInternally( hwnd );
CComQIPtr< IDispatch, &IID_IDispatch > pIDispToSend( pPeerToSend );
// create rectangle structure
CComPtr<IDispatch> pdispRectangle;
HRESULT hr = GetUnoStruct( L"com.sun.star.awt.Rectangle", pdispRectangle );
if( !SUCCEEDED( hr ) ) return hr;
OLECHAR const * sRectMemberNames[4] = { L"X",
L"Y",
L"Width",
L"Height" };
CComVariant pRectVariant[4];
pRectVariant[0] = pRectVariant[1] = pRectVariant[2] = pRectVariant[3] = CComVariant( 0 );
hr = PutPropertiesToIDisp( pdispRectangle, sRectMemberNames, pRectVariant, 4 );
if( !SUCCEEDED( hr ) ) return hr;
// create WindowDescriptor structure
CComPtr<IDispatch> pdispWinDescr;
hr = GetUnoStruct( L"com.sun.star.awt.WindowDescriptor", pdispWinDescr );
if( !SUCCEEDED( hr ) ) return hr;
// fill in descriptor with info
OLECHAR const * sDescriptorMemberNames[6] = { L"Type",
L"WindowServiceName",
L"ParentIndex",
L"Parent",
L"Bounds",
L"WindowAttributes" };
CComVariant pDescriptorVar[6];
pDescriptorVar[0] = CComVariant( 0 );
pDescriptorVar[1] = CComVariant( L"workwindow" );
pDescriptorVar[2] = CComVariant( 1 );
pDescriptorVar[3] = CComVariant( pIDispToSend );
pDescriptorVar[4] = CComVariant( pdispRectangle );
pDescriptorVar[5] = CComVariant( 33 );
hr = PutPropertiesToIDisp( pdispWinDescr, sDescriptorMemberNames, pDescriptorVar, 6 );
if( !SUCCEEDED( hr ) ) return hr;
// create XToolkit instance
CComPtr<IDispatch> pdispToolkit;
CComVariant aServiceName( L"com.sun.star.awt.Toolkit" );
hr = GetIDispByFunc( mpDispFactory, L"createInstance", &aServiceName, 1, pdispToolkit );
if( !SUCCEEDED( hr ) ) return hr;
// create window with toolkit
CComVariant aWinDescr( pdispWinDescr );
hr = GetIDispByFunc( pdispToolkit, L"createWindow", &aWinDescr, 1, mpDispWin );
if( !SUCCEEDED( hr ) ) return hr;
// create frame
aServiceName = CComVariant( L"com.sun.star.frame.Task" );
hr = GetIDispByFunc( mpDispFactory, L"createInstance", &aServiceName, 1, mpDispFrame );
if( !SUCCEEDED( hr ) || !mpDispFrame )
{
// the interface com.sun.star.frame.Task is removed in 6.1
// but the interface com.sun.star.frame.Frame has some bugs in 6.0
aServiceName = CComVariant( L"com.sun.star.frame.Frame" );
hr = GetIDispByFunc( mpDispFactory, L"createInstance", &aServiceName, 1, mpDispFrame );
if( !SUCCEEDED( hr ) ) return hr;
}
// initialize frame
CComVariant dummyResult;
CComVariant aDispWin( mpDispWin );
hr = ExecuteFunc( mpDispFrame, L"initialize", &aDispWin, 1, &dummyResult );
if( !SUCCEEDED( hr ) ) return hr;
// set some properties to the layout manager, ignore errors for now
SetLayoutManagerProps();
// create desktop
CComPtr<IDispatch> pdispDesktop;
aServiceName = CComVariant( L"com.sun.star.frame.Desktop" );
hr = GetIDispByFunc( mpDispFactory, L"createInstance", &aServiceName, 1, pdispDesktop );
if( !SUCCEEDED( hr ) ) return hr;
// create tree of frames
CComPtr<IDispatch> pdispChildren;
hr = GetIDispByFunc( pdispDesktop, L"getFrames", nullptr, 0, pdispChildren );
if( !SUCCEEDED( hr ) ) return hr;
// insert new frame into desktop hierarchy
CComVariant aDispFrame( mpDispFrame );
hr = ExecuteFunc( pdispChildren, L"append", &aDispFrame, 1, &dummyResult );
if( !SUCCEEDED( hr ) ) return hr;
// initialize window
CComVariant aTransparent( (long)0xFFFFFFFF );
hr = ExecuteFunc( mpDispWin, L"setBackground", &aTransparent, 1, &dummyResult );
if( !SUCCEEDED( hr ) ) return hr;
CComVariant aTrue( TRUE );
hr = ExecuteFunc( mpDispWin, L"setVisible", &aTrue, 1, &dummyResult );
if( !SUCCEEDED( hr ) ) return hr;
CComVariant aPosArgs[5];
aPosArgs[4] = CComVariant( 0 );
aPosArgs[3] = CComVariant( 0 );
aPosArgs[2] = CComVariant( width );
aPosArgs[1] = CComVariant( height );
aPosArgs[0] = CComVariant( 12 );
hr = ExecuteFunc( mpDispWin, L"setPosSize", aPosArgs, 5, &dummyResult );
if( !SUCCEEDED( hr ) ) return hr;
// create frame locker if there is such service
aServiceName = CComVariant( L"com.sun.star.embed.InstanceLocker" );
hr = GetIDispByFunc( mpDispFactory, L"createInstance", &aServiceName, 1, mpInstanceLocker );
if( SUCCEEDED( hr ) && mpInstanceLocker )
{
SAFEARRAY FAR* pInitVals = SafeArrayCreateVector( VT_VARIANT, 0, 3 );
// the first sequence element
long nInitInd = 0;
CComVariant pFrameVariant( mpDispFrame );
SafeArrayPutElement( pInitVals, &nInitInd, &pFrameVariant );
// the second sequence element
nInitInd = 1;
CComVariant pStrArr( 1 );
SafeArrayPutElement( pInitVals, &nInitInd, &pStrArr );
// the third sequence element
nInitInd = 2;
CComPtr<IDispatch> pdispValueObj;
hr = GetIDispByFunc( mpDispFactory, L"Bridge_GetValueObject", nullptr, 0, pdispValueObj );
if( !SUCCEEDED( hr ) || !pdispValueObj ) return hr;
CComVariant aValueArgs[2];
aValueArgs[1] = CComVariant( L"com.sun.star.embed.XActionsApproval" );
CComPtr< CComObject< SOActionsApproval > > pApproval( new CComObject<SOActionsApproval>() );
aValueArgs[0] = CComVariant ( pApproval );
hr = ExecuteFunc( pdispValueObj, L"Set", aValueArgs, 2, &dummyResult );
if( !SUCCEEDED( hr ) ) return hr;
CComVariant aValueObj( pdispValueObj );
SafeArrayPutElement( pInitVals, &nInitInd, &aValueObj );
// execute initialize()
CComVariant aVarInitVals;
aVarInitVals.vt = VT_ARRAY | VT_VARIANT; aVarInitVals.parray = pInitVals;
hr = ExecuteFunc( mpInstanceLocker, L"initialize", &aVarInitVals, 1, &dummyResult );
if( !SUCCEEDED( hr ) ) return hr;
}
return S_OK;
}
HRESULT CSOActiveX::CallLoadComponentFromURL1PBool( OLECHAR const * sUrl, OLECHAR const * sArgName, BOOL sArgVal )
{
SAFEARRAY FAR* pPropVals = SafeArrayCreateVector( VT_DISPATCH, 0, 1 );
long ix = 0;
CComPtr<IDispatch> pdispPropVal;
HRESULT hr = GetUnoStruct( L"com.sun.star.beans.PropertyValue", pdispPropVal );
if( !SUCCEEDED( hr ) ) return hr;
OLECHAR const * sPropMemberNames[2] = { L"Name", L"Value" };
CComVariant pPropVar[2];
pPropVar[0] = CComVariant( sArgName );
pPropVar[1].vt = VT_BOOL; pPropVar[1].boolVal = sArgVal ? VARIANT_TRUE : VARIANT_FALSE ;
hr = PutPropertiesToIDisp( pdispPropVal, sPropMemberNames, pPropVar, 2 );
if( !SUCCEEDED( hr ) ) return hr;
SafeArrayPutElement( pPropVals, &ix, pdispPropVal );
CComVariant aDispArgs[4];
aDispArgs[3] = CComVariant( sUrl );
aDispArgs[2] = CComVariant( L"_self" );
aDispArgs[1] = CComVariant( 0 );
// aDispArgs[0] = CComVariant( pPropVals ); such constructor is not defined ??!
aDispArgs[0].vt = VT_ARRAY | VT_DISPATCH; aDispArgs[0].parray = pPropVals;
CComVariant dummyResult;
hr = ExecuteFunc( mpDispFrame, L"loadComponentFromURL", aDispArgs, 4, &dummyResult );
if( !SUCCEEDED( hr ) ) return hr;
return S_OK;
}
HRESULT CSOActiveX::CallDispatchMethod( OLECHAR const * sUrl,
CComVariant* aArgNames,
CComVariant* aArgVals,
unsigned int count )
{
CComPtr<IDispatch> pdispURL;
HRESULT hr = GetUrlStruct( sUrl, pdispURL );
if( !SUCCEEDED( hr ) ) return hr;
CComPtr<IDispatch> pdispXDispatch;
CComVariant aArgs[3];
aArgs[2] = CComVariant( pdispURL );
aArgs[1] = CComVariant( L"" );
aArgs[0] = CComVariant( (int)0 );
hr = GetIDispByFunc( mpDispFrame,
L"queryDispatch",
aArgs,
3,
pdispXDispatch );
if( !SUCCEEDED( hr ) ) return hr;
SAFEARRAY FAR* pPropVals = SafeArrayCreateVector( VT_DISPATCH, 0, count );
for( long ix = 0; ix < (long)count; ix ++ )
{
CComPtr<IDispatch> pdispPropVal;
hr = GetUnoStruct( L"com.sun.star.beans.PropertyValue", pdispPropVal );
if( !SUCCEEDED( hr ) ) return hr;
OLECHAR const * sPropMemberNames[2] = { L"Name", L"Value" };
CComVariant pPropVar[2];
pPropVar[0] = aArgNames[ix];
pPropVar[1] = aArgVals[ix];
hr = PutPropertiesToIDisp( pdispPropVal, sPropMemberNames, pPropVar, 2 );
if( !SUCCEEDED( hr ) ) return hr;
SafeArrayPutElement( pPropVals, &ix, pdispPropVal );
}
CComVariant aDispArgs[2];
aDispArgs[1] = CComVariant( pdispURL );
// aDispArgs[0] = CComVariant( pPropVals ); such constructor is not defined ??!
aDispArgs[0].vt = VT_ARRAY | VT_DISPATCH; aDispArgs[0].parray = pPropVals;
CComVariant dummyResult;
hr = ExecuteFunc( pdispXDispatch, L"dispatch", aDispArgs, 2, &dummyResult );
if( !SUCCEEDED( hr ) ) return hr;
return S_OK;
}
void CSOActiveX::CallbackCreateXInputStream( CBindStatusCallback<CSOActiveX>* /*pbsc*/, BYTE* pBytes, DWORD dwSize )
{
if ( mbReadyForActivation )
return;
BOOL bSuccess = FALSE;
BOOL bFinishDownload = FALSE;
if ( !pBytes )
{
// means the download is finished, dwSize contains hresult
bFinishDownload = TRUE;
if ( SUCCEEDED( dwSize ) )
bSuccess = TRUE;
}
else
{
HRESULT hr = S_OK;
if ( !mpDispTempFile )
{
CComVariant aServiceName( L"com.sun.star.io.TempFile" );
hr = GetIDispByFunc( mpDispFactory,
L"createInstance",
&aServiceName,
1,
mpDispTempFile );
}
if( SUCCEEDED( hr ) && mpDispTempFile )
{
SAFEARRAY FAR* pDataArray = SafeArrayCreateVector( VT_I1, 0, dwSize );
if ( pDataArray )
{
hr = SafeArrayLock( pDataArray );
if ( SUCCEEDED( hr ) )
{
for( DWORD ix = 0; ix < dwSize; ix++ )
static_cast<BYTE*>(pDataArray->pvData)[ix] = pBytes[ix];
hr = SafeArrayUnlock( pDataArray );
if ( SUCCEEDED( hr ) )
{
CComVariant aArgs[1];
aArgs[0].vt = VT_ARRAY | VT_I1; aArgs[0].parray = pDataArray;
CComVariant dummyResult;
hr = ExecuteFunc( mpDispTempFile, L"writeBytes", aArgs, 1, &dummyResult );
if( SUCCEEDED( hr ) )
bSuccess = TRUE;
}
}
}
}
}
if ( !bSuccess )
{
// the download failed, let StarOffice download
bFinishDownload = TRUE;
mpDispTempFile = CComPtr< IDispatch >();
}
if ( bFinishDownload )
{
// trigger the loading now
mbLoad = TRUE;
mbReadyForActivation = TRUE;
Invalidate();
UpdateWindow();
}
}
HRESULT CSOActiveX::LoadURLToFrame( )
{
CComVariant aArgNames[4] = { L"ReadOnly", L"ViewOnly", L"AsTemplate", L"InputStream" };
CComVariant aArgVals[4];
unsigned int nCount = 3; // the 4-th argument is used only if the stream can be retrieved
aArgVals[0].vt = VT_BOOL; aArgVals[0].boolVal = mbViewOnly ? VARIANT_TRUE : VARIANT_FALSE;
aArgVals[1].vt = VT_BOOL; aArgVals[1].boolVal = mbViewOnly ? VARIANT_TRUE : VARIANT_FALSE;
aArgVals[2].vt = VT_BOOL; aArgVals[2].boolVal = VARIANT_FALSE;
if ( mpDispTempFile )
{
aArgVals[3] = CComVariant( mpDispTempFile );
nCount = 4;
}
HRESULT hr = CallDispatchMethod( mCurFileUrl, aArgNames, aArgVals, nCount );
if( !SUCCEEDED( hr ) ) return hr;
CComVariant aBarName( L"MenuBarVisible" );
CComVariant aBarVis;
aBarVis.vt = VT_BOOL; aBarVis.boolVal = VARIANT_FALSE;
hr = CallDispatchMethod( L"slot:6661", &aBarName, &aBarVis, 1 );
// does not work for some documents, but it is no error
// if( !SUCCEEDED( hr ) ) return hr;
// try to get the model and set the presetation specific property, the setting will fail for other document formats
CComPtr<IDispatch> pdispController;
hr = GetIDispByFunc( mpDispFrame, L"getController", nullptr, 0, pdispController );
if ( SUCCEEDED( hr ) && pdispController )
{
CComPtr<IDispatch> pdispModel;
hr = GetIDispByFunc( pdispController, L"getModel", nullptr, 0, pdispModel );
if ( SUCCEEDED( hr ) && pdispModel )
{
CComPtr<IDispatch> pdispPres;
hr = GetIDispByFunc( pdispModel, L"getPresentation", nullptr, 0, pdispPres );
if ( SUCCEEDED( hr ) && pdispPres )
{
// this is a presentation
// let the slide show be shown in the document window
OLECHAR const * pPropName = L"IsFullScreen";
CComVariant pPresProp;
pPresProp.vt = VT_BOOL; pPresProp.boolVal = VARIANT_FALSE ;
hr = PutPropertiesToIDisp( pdispPres, &pPropName, &pPresProp, 1 );
// start the slide show
if ( SUCCEEDED( hr ) )
{
CComVariant dummyResult;
ExecuteFunc( pdispPres, L"Start", nullptr, 0, &dummyResult );
}
}
}
}
// create dispatch interceptor
mpDispatchInterceptor = new CComObject< SODispatchInterceptor >();
mpDispatchInterceptor->AddRef();
mpDispatchInterceptor->SetParent( this );
CComQIPtr< IDispatch, &IID_IDispatch > pIDispDispInter( mpDispatchInterceptor );
// register dispatch interceptor in the frame
CComVariant aDispVariant( pIDispDispInter );
CComVariant dummyResult;
hr = ExecuteFunc( mpDispFrame,
L"registerDispatchProviderInterceptor",
&aDispVariant,
1,
&dummyResult );
if( !SUCCEEDED( hr ) ) return hr;
return S_OK;
}
SOVersion CSOActiveX::GetVersionConnected()
{
SOVersion bResult = SO_NOT_DETECTED;
if( mpDispFactory )
{
// create ConfigurationProvider instance
CComPtr<IDispatch> pdispConfProv;
CComVariant aServiceName( L"com.sun.star.configuration.ConfigurationProvider" );
HRESULT hr = GetIDispByFunc( mpDispFactory,
L"createInstance",
&aServiceName,
1,
pdispConfProv );
if( SUCCEEDED( hr ) && pdispConfProv )
{
CComPtr<IDispatch> pdispConfAccess;
SAFEARRAY* pInitParams = SafeArrayCreateVector( VT_VARIANT, 0, 1 );
if( pInitParams )
{
long ix = 0;
CComVariant aConfPath( L"org.openoffice.Setup" );
SafeArrayPutElement( pInitParams, &ix, &aConfPath );
CComVariant aArgs[2];
aArgs[1] = CComVariant( L"com.sun.star.configuration.ConfigurationAccess" );
aArgs[0].vt = VT_ARRAY | VT_VARIANT; aArgs[0].parray = pInitParams;
hr = GetIDispByFunc( pdispConfProv,
L"createInstanceWithArguments",
aArgs,
2,
pdispConfAccess );
if( SUCCEEDED( hr ) && pdispConfAccess )
{
CComVariant aOfficeName;
CComVariant aProductName( L"Product/ooName" );
hr = ExecuteFunc( pdispConfAccess,
L"getByHierarchicalName",
&aProductName,
1,
&aOfficeName );
if( SUCCEEDED( hr ) && aOfficeName.vt == VT_BSTR )
{
CComVariant aOfficeVersion;
CComVariant aProductVersion( L"Product/ooSetupVersion" );
hr = ExecuteFunc( pdispConfAccess,
L"getByHierarchicalName",
&aProductVersion,
1,
&aOfficeVersion );
if( SUCCEEDED( hr ) && aOfficeVersion.vt == VT_BSTR )
{
USES_CONVERSION;
if( !strcmp( OLE2T( aOfficeName.bstrVal ), "StarOffice" ) )
{
if( !strncmp( OLE2T( aOfficeVersion.bstrVal ), "6.1", 3 ) )
bResult = SO_61;
else if( !strncmp( OLE2T( aOfficeVersion.bstrVal ), "6.0", 3 ) )
bResult = SO_60;
else if( !strncmp( OLE2T( aOfficeVersion.bstrVal ), "5.2", 3 ) )
bResult = SO_52;
else
bResult = SO_UNKNOWN;
}
else // OpenOffice
{
if( !strncmp( OLE2T( aOfficeVersion.bstrVal ), "1.1", 3 ) )
bResult = OO_11;
else if( !strncmp( OLE2T( aOfficeVersion.bstrVal ), "1.0", 3 ) )
bResult = OO_10;
else
bResult = OO_UNKNOWN;
}
}
}
}
}
}
}
return bResult;
}
class LockingGuard
{
BOOL& mbLocked;
public:
explicit LockingGuard( BOOL& bLocked )
: mbLocked( bLocked )
{
mbLocked = TRUE;
}
~LockingGuard()
{
mbLocked = FALSE;
}
};
HRESULT CSOActiveX::OnDrawAdvanced( ATL_DRAWINFO& di )
{
// This method is called only in main thread, no need to lock it
// Get read of reentrance problems
if ( mbDrawLocked )
return S_OK;
LockingGuard aGuard( mbDrawLocked );
if( m_spInPlaceSite && mCurFileUrl && mbReadyForActivation )
{
HWND hwnd;
HRESULT hr = m_spInPlaceSite->GetWindow( &hwnd );
if( !SUCCEEDED( hr ) ) return hr;
if( mParentWin != hwnd || !mOffWin )
{
if( mpDispFrame )
{
CComVariant dummyResult;
CComVariant aPropVar;
aPropVar.vt = VT_BOOL; aPropVar.boolVal = VARIANT_FALSE;
(void) ExecuteFunc( mpDispFrame, L"close", &aPropVar, 1, &dummyResult );
mpDispFrame = CComPtr<IDispatch>();
}
mParentWin = hwnd;
mOffWin = CreateWindowW(
STAROFFICE_WINDOWCLASS,
L"OfficeContainer",
WS_CHILD | WS_CLIPCHILDREN | WS_BORDER,
di.prcBounds->left,
di.prcBounds->top,
di.prcBounds->right - di.prcBounds->left,
di.prcBounds->bottom - di.prcBounds->top,
mParentWin,
nullptr,
nullptr,
nullptr );
::ShowWindow( mOffWin, SW_SHOW );
}
else
{
RECT aRect;
::GetWindowRect( mOffWin, &aRect );
if( aRect.left != di.prcBounds->left || aRect.top != di.prcBounds->top
|| aRect.right != di.prcBounds->right || aRect.bottom != di.prcBounds->bottom )
{
// on this state the office window should exist already
::SetWindowPos( mOffWin,
HWND_TOP,
di.prcBounds->left,
di.prcBounds->top,
di.prcBounds->right - di.prcBounds->left,
di.prcBounds->bottom - di.prcBounds->top,
SWP_NOZORDER );
CComVariant aPosArgs[5];
aPosArgs[4] = CComVariant( 0 );
aPosArgs[3] = CComVariant( 0 );
aPosArgs[2] = CComVariant( int(di.prcBounds->right - di.prcBounds->left) );
aPosArgs[1] = CComVariant( int(di.prcBounds->bottom - di.prcBounds->top) );
aPosArgs[0] = CComVariant( 12 );
CComVariant dummyResult;
hr = ExecuteFunc( mpDispWin, L"setPosSize", aPosArgs, 5, &dummyResult );
if( !SUCCEEDED( hr ) ) return hr;
}
}
if( !mnVersion )
{
OutputError_Impl( mOffWin, CS_E_INVALID_VERSION );
return E_FAIL;
}
if( ! mpDispFrame )
{
hr = CreateFrameOldWay( mOffWin,
di.prcBounds->right - di.prcBounds->left,
di.prcBounds->bottom - di.prcBounds->top );
if( !SUCCEEDED( hr ) )
{
// if the frame can not be opened do not try any more
mbReadyForActivation = FALSE;
OutputError_Impl( mOffWin, STG_E_ABNORMALAPIEXIT );
return hr;
}
}
if( mbLoad )
{
hr = LoadURLToFrame();
mbLoad = FALSE;
if( !SUCCEEDED( hr ) )
{
// if the document can not be opened do not try any more
mbReadyForActivation = FALSE;
OutputError_Impl( mOffWin, STG_E_ABNORMALAPIEXIT );
return hr;
}
}
}
else
{
// activate the fallback
CComControl<CSOActiveX>::OnDrawAdvanced( di );
}
return S_OK;
}
HRESULT CSOActiveX::OnDraw( ATL_DRAWINFO& di )
{
// fallback that is activated by the parent class
if ( di.hdcDraw )
FillRect( di.hdcDraw, reinterpret_cast<RECT const *>(di.prcBounds), reinterpret_cast<HBRUSH>(COLOR_BACKGROUND) );
return S_OK;
}
STDMETHODIMP CSOActiveX::SetClientSite( IOleClientSite* aClientSite )
{
HRESULT hr = IOleObjectImpl<CSOActiveX>::SetClientSite( aClientSite );
if( !aClientSite )
{
//ATLASSERT( mWebBrowser2 );
if( mWebBrowser2 )
AtlUnadvise( mWebBrowser2, DIID_DWebBrowserEvents2, mCookie );
return hr;
}
CComPtr<IOleContainer> aContainer;
m_spClientSite->GetContainer( &aContainer );
// ATLASSERT( aContainer );
if( SUCCEEDED( hr ) && aContainer )
{
CComQIPtr<IServiceProvider, &IID_IServiceProvider> aServiceProvider( aContainer );
//ATLASSERT( aServiceProvider );
if( aServiceProvider )
{
aServiceProvider->QueryService( SID_SInternetExplorer,
IID_IWebBrowser,
reinterpret_cast<void**>(&mWebBrowser2) );
// ATLASSERT( mWebBrowser2 );
if( mWebBrowser2 )
AtlAdvise( mWebBrowser2, GetUnknown(), DIID_DWebBrowserEvents2, &mCookie );
}
}
return hr;
}
STDMETHODIMP CSOActiveX::Invoke(DISPID dispidMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS* pDispParams,
VARIANT* pvarResult,
EXCEPINFO* pExcepInfo,
UINT* puArgErr)
{
if (riid != IID_NULL)
return DISP_E_UNKNOWNINTERFACE;
if (!pDispParams)
return DISP_E_PARAMNOTOPTIONAL;
if ( dispidMember == DISPID_ONQUIT )
Cleanup();
IDispatchImpl<ISOActiveX, &IID_ISOActiveX,
&LIBID_SO_ACTIVEXLib>::Invoke(
dispidMember, riid, lcid, wFlags, pDispParams,
pvarResult, pExcepInfo, puArgErr);
return S_OK;
}
HRESULT CSOActiveX::GetURL( const OLECHAR* url,
const OLECHAR* target )
{
CComVariant aEmpty1, aEmpty2, aEmpty3;
CComVariant aUrl( url );
CComVariant aTarget;
if ( target )
aTarget = CComVariant( target );
return mWebBrowser2->Navigate2( &aUrl,
&aEmpty1,
&aTarget,
&aEmpty2,
&aEmpty3 );
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */