/* -*- 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
#include "StdAfx2.h"
#include <so_activex.h>
#include "SOActiveX.h"
#include "SOComWindowPeer.h"
#include "SODispatchInterceptor.h"
#include "SOActionsApproval.h"
#include "com_uno_helper.h"
#define STAROFFICE_WINDOWCLASS L
"SOParentWindow"
static void OutputError_Impl( HWND hw, HRESULT ErrorCode )
{
LPWSTR sMessage = nullptr;
FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_
INSERTS,
nullptr,
ErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
reinterpret_cast <LPWSTR>(&sMessage),
0,
nullptr
);
MessageBoxW( hw, sMessage, nullptr, MB_OK | MB_ICONINFORMATION );
HeapFree( GetProcessHeap(), 0, 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;
}
static 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;
}
static 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, IID_PPV_ARGS(&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* 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;
}
COM_DECLSPEC_NOTHROW STDMETHODIMP CSOActiveX::InitNew ()
{
mnVersion = GetVersionConnected();
mbLoad = TRUE ;
return S_OK;
}
COM_DECLSPEC_NOTHROW STDMETHODIMP CSOActiveX::Load ( LPSTREAM /*pStm*/ )
{
mnVersion = GetVersionConnected();
mbLoad = TRUE ;
// may be later?
// for now just ignore
return S_OK;
}
COM_DECLSPEC_NOTHROW STDMETHODIMP CSOActiveX::Load( LPPROPERTYBAG pPropBag, LPERRORLOG /*pErrorLog*/ )
{
mnVersion = GetVersionConnected();
CComPtr<IPropertyBag2> pPropBag2;
HRESULT hr = pPropBag->QueryInterface(&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;
}
for ( unsigned long ind = 0; ind < aNum; ind++ )
{
// all information from the 'object' tag is in strings
if (aVal[ind].vt == VT_BSTR && !wcscmp(aPropNames[ind].pstrName, L"src" ))
{
mCurFileUrl.AssignBSTR(aVal[ind].bstrVal);
}
else if ( aVal[ind].vt == VT_BSTR
&& !wcscmp(aPropNames[ind].pstrName, L"readonly" ))
{
if (!wcscmp(aVal[ind].bstrVal, L"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, 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* 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* 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* pPropVals = SafeArrayCreateVector(VT_DISPATCH, 0, count);
for ( LONG ix = 0; ix < static_cast <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* 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;
// try to get the model and set the presentation 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 )
{
if (!wcscmp(aOfficeName.bstrVal, L"StarOffice" ))
{
if (!wcsncmp(aOfficeVersion.bstrVal, L"6.1" , 3))
bResult = SO_61;
else if (!wcsncmp(aOfficeVersion.bstrVal, L"6.0" , 3))
bResult = SO_60;
else if (!wcsncmp(aOfficeVersion.bstrVal, L"5.2" , 3))
bResult = SO_52;
else
bResult = SO_UNKNOWN;
}
else // OpenOffice
{
if (!wcsncmp(aOfficeVersion.bstrVal, L"1.1" , 3))
bResult = OO_11;
else if (!wcsncmp(aOfficeVersion.bstrVal, L"1.0" , 3))
bResult = OO_10;
else
bResult = OO_UNKNOWN;
}
}
}
}
}
}
}
return bResult;
}
namespace {
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 == SO_NOT_DETECTED)
{
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;
}
COM_DECLSPEC_NOTHROW 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_PPV_ARGS(&mWebBrowser2));
// ATLASSERT( mWebBrowser2 );
if ( mWebBrowser2 )
AtlAdvise( mWebBrowser2, GetUnknown(), DIID_DWebBrowserEvents2, &mCookie );
}
}
return hr;
}
COM_DECLSPEC_NOTHROW 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: */
Messung V0.5 C=94 H=96 G=94
¤ Dauer der Verarbeitung: 0.5 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland