diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /extensions/source/activex | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'extensions/source/activex')
22 files changed, 3684 insertions, 0 deletions
diff --git a/extensions/source/activex/README.txt b/extensions/source/activex/README.txt new file mode 100644 index 000000000..50c209150 --- /dev/null +++ b/extensions/source/activex/README.txt @@ -0,0 +1,33 @@ +Description. + +The StarOffice ActiveX control shows an example of access to UNO through COM technology. +It requires a properly installed StarOffice version 6.0/6.1 or OpenOffice 1.0. +This is a Lite ActiveX control so it can be used only in containers that +allows to use such controls. + +Pressing to any link to staroffice document should activate the control. +So the document will be opened in ReadOnly mode. + +Also it can be activated with an <OBJECT> tag from a html-page. +Without any parameters for an object tag a new writer document will be +opened for editing. Possible parameters are + src - full URL to the file that should be edited/viewed; + it can contain "private:factory/..." URLs to open new documents + for edit, for example "private:factory/swriter" + readonly - the default value is "true", in case it is set to any other + value the document is opened for editing + +As any ActiveX control this one should be registered. +To let MSIE register it itself the "CODEBASE" parameter +for the "OBJECT" tag should be specified +with a URL to the library "so_activex.dll". +The example of registration with "OBJECT" tag is in example.html. + +Also it can be done using regsvr32 application. +To do it please write +<Path to Windows installation>\System32\regsvr32 so_activex.dll + +To unregister the control please use /u option: +<Path to Windows installation>\system32\regsvr32 so_activex.dll /u + + diff --git a/extensions/source/activex/SOActionsApproval.cxx b/extensions/source/activex/SOActionsApproval.cxx new file mode 100644 index 000000000..a40921662 --- /dev/null +++ b/extensions/source/activex/SOActionsApproval.cxx @@ -0,0 +1,58 @@ +/* -*- 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 . + */ + +// SOActionsApproval.cpp : Implementation of CHelpApp and DLL registration. + +#include <sal/config.h> + +#include <cstddef> + +#include "StdAfx2.h" + +#include "SOActionsApproval.h" +#include <sal/macros.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 + +COM_DECLSPEC_NOTHROW STDMETHODIMP SOActionsApproval::InterfaceSupportsErrorInfo(REFIID riid) +{ + static const IID* arr[] = { + &IID_ISOActionsApproval, + }; + + for (std::size_t i = 0; i < SAL_N_ELEMENTS(arr); i++) + { +#ifdef _MSC_VER + if (InlineIsEqualGUID(*arr[i], riid)) +#else + if (::ATL::InlineIsEqualGUID(*arr[i], riid)) +#endif + return S_OK; + } + return S_FALSE; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/SOActionsApproval.h b/extensions/source/activex/SOActionsApproval.h new file mode 100644 index 000000000..2484e7462 --- /dev/null +++ b/extensions/source/activex/SOActionsApproval.h @@ -0,0 +1,105 @@ +/* -*- 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 . + */ + +// SOActionsApproval.h: Definition of the SOActionsApproval class + +#pragma once + +#ifdef _MSC_VER +#pragma once +#endif + +#include "resource.h" +#include <ExDispID.h> +#include <ExDisp.h> +#include <shlguid.h> + +#include <atlctl.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 + +// SOActionsApproval + +class SOActionsApproval : + public IDispatchImpl<ISOActionsApproval, &IID_ISOActionsApproval, &LIBID_SO_ACTIVEXLib>, + public ISupportErrorInfo, + public CComObjectRoot, + public CComCoClass<SOActionsApproval,&CLSID_SOActionsApproval> +{ +public: + SOActionsApproval() {} + virtual ~SOActionsApproval() {} + +BEGIN_COM_MAP(SOActionsApproval) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(ISOActionsApproval) + COM_INTERFACE_ENTRY(ISupportErrorInfo) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif +END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif +DECLARE_NOT_AGGREGATABLE(SOActionsApproval) +// Remove the comment from the line above if you don't want your object to +// support aggregation. + +DECLARE_REGISTRY_RESOURCEID(IDR_SODOCUMENTEVENTLISTENER) + +// ISupportsErrorInfo + STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) override; + +// ISOActionsApproval + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE approveAction( + /* [in] */ long nActionID, + /* [retval][out] */ boolean *pbApproval) override + { + // only PreventClose is approved + USES_CONVERSION; + *pbApproval = ( nActionID == 1 ); + + return S_OK; + } + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_Bridge_implementedInterfaces( + /* [retval][out] */ SAFEARRAY __RPC_FAR * __RPC_FAR *pVal) override + { + *pVal = SafeArrayCreateVector( VT_BSTR, 0, 1 ); + + if( !*pVal ) + return E_FAIL; + + LONG ix = 0; + CComBSTR aInterface( OLESTR( "com.sun.star.embed.XActionsApproval" ) ); + SafeArrayPutElement( *pVal, &ix, aInterface ); + + return S_OK; + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/SOActionsApproval.rgs b/extensions/source/activex/SOActionsApproval.rgs new file mode 100644 index 000000000..543320813 --- /dev/null +++ b/extensions/source/activex/SOActionsApproval.rgs @@ -0,0 +1,24 @@ +HKCR +{ +9F3697AC-7A18-4335-AF0A-65FAC2C35CC1 + so_activex.SOActionsApproval.1 = s 'SOActionsApproval Class' + { + CLSID = s '{9F3697AC-7A18-4335-AF0A-65FAC2C35CC1}' + } + so_activex.SOActionsApproval = s 'SOActionsApproval Class' + { + CLSID = s '{9F3697AC-7A18-4335-AF0A-65FAC2C35CC1}' + } + NoRemove CLSID + { + ForceRemove {9F3697AC-7A18-4335-AF0A-65FAC2C35CC1} = s 'SOActionsApproval Class' + { + ProgID = s 'so_activex.SOActionsApproval.1' + VersionIndependentProgID = s 'so_activex.SOActionsApproval' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'both' + } + } + } +} diff --git a/extensions/source/activex/SOActiveX.cxx b/extensions/source/activex/SOActiveX.cxx new file mode 100644 index 000000000..88b3ad769 --- /dev/null +++ b/extensions/source/activex/SOActiveX.cxx @@ -0,0 +1,1162 @@ +/* -*- 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 "SOActiveX.h" +#include "SOComWindowPeer.h" +#include "SODispatchInterceptor.h" +#include "SOActionsApproval.h" +#include "com_uno_helper.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 + +#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, __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* 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(); + + 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; + } + + 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_IWebBrowser, + reinterpret_cast<void**>(&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: */ diff --git a/extensions/source/activex/SOActiveX.h b/extensions/source/activex/SOActiveX.h new file mode 100644 index 000000000..37d983ae9 --- /dev/null +++ b/extensions/source/activex/SOActiveX.h @@ -0,0 +1,212 @@ +/* -*- 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.h : Declaration of the CSOActiveX + +#pragma once + +#include "resource.h" + +#include <ExDispID.h> +#include <ExDisp.h> +#include <shlguid.h> + +#include <atlctl.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 + +class SODispatchInterceptor; + +enum SOVersion { + SO_NOT_DETECTED = 0, + SO_52, + SO_60, + SO_61, + SO_UNKNOWN, + OO_10, + OO_11, + OO_UNKNOWN +}; + + +// CSOActiveX +class ATL_NO_VTABLE CSOActiveX : + public CComObjectRootEx<CComSingleThreadModel>, + public IDispatchImpl<ISOActiveX, &IID_ISOActiveX, &LIBID_SO_ACTIVEXLib>, + public CComControl<CSOActiveX>, + public IPersistStreamInitImpl<CSOActiveX>, + public IOleControlImpl<CSOActiveX>, + public IOleObjectImpl<CSOActiveX>, + public IOleInPlaceActiveObjectImpl<CSOActiveX>, + public IViewObjectExImpl<CSOActiveX>, + public IOleInPlaceObjectWindowlessImpl<CSOActiveX>, +// public IConnectionPointContainerImpl<CSOActiveX>, + public CComCoClass<CSOActiveX, &CLSID_SOActiveX>, +// public CProxy_ItryPluginEvents< CSOActiveX >, + public IPersistPropertyBagImpl< CSOActiveX >, + public IProvideClassInfo2Impl< &CLSID_SOActiveX, + &DIID__ISOActiveXEvents, + &LIBID_SO_ACTIVEXLib >, + public IObjectSafetyImpl< CSOActiveX, + INTERFACESAFE_FOR_UNTRUSTED_DATA > +{ +protected: + CComPtr<IWebBrowser2> mWebBrowser2; + DWORD mCookie; + + CComPtr<IDispatch> mpDispFactory; + CComPtr<IDispatch> mpDispFrame; + CComPtr<IDispatch> mpInstanceLocker; + CComPtr<IDispatch> mpDispWin; + CComBSTR mCurFileUrl; + BOOL mbLoad; + BOOL mbViewOnly; + WNDCLASSW mPWinClass; + HWND mParentWin; + HWND mOffWin; + + SODispatchInterceptor* mpDispatchInterceptor; + SOVersion mnVersion; + + BOOL mbReadyForActivation; + CComPtr<IDispatch> mpDispTempFile; + + bool mbDrawLocked; + +public: + CSOActiveX(); + ~CSOActiveX() override; + +DECLARE_REGISTRY_RESOURCEID(IDR_SOACTIVEX) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CSOActiveX) + COM_INTERFACE_ENTRY(ISOActiveX) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(IViewObjectEx) + COM_INTERFACE_ENTRY(IViewObject2) + COM_INTERFACE_ENTRY(IViewObject) + COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless) + COM_INTERFACE_ENTRY(IOleInPlaceObject) + COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless) + COM_INTERFACE_ENTRY(IOleInPlaceActiveObject) + COM_INTERFACE_ENTRY(IOleControl) + COM_INTERFACE_ENTRY(IOleObject) + COM_INTERFACE_ENTRY(IPersistStreamInit) + COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit) +// COM_INTERFACE_ENTRY(IConnectionPointContainer) + COM_INTERFACE_ENTRY(IProvideClassInfo) + COM_INTERFACE_ENTRY(IProvideClassInfo2) + COM_INTERFACE_ENTRY(IPersistPropertyBag) + COM_INTERFACE_ENTRY(IObjectSafety) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif +END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winvalid-offsetof" + // offset of on non-standard-layout type '_PropMapClass' (aka 'CSOActiveX'), + // expanded from macro 'PROP_DATA_ENTRY' +#endif +BEGIN_PROP_MAP(CSOActiveX) + PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4) + PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4) + // Example entries + // PROP_ENTRY("Property Description", dispid, clsid) + // PROP_PAGE(CLSID_StockColorPage) +END_PROP_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +BEGIN_CONNECTION_POINT_MAP(CSOActiveX) +END_CONNECTION_POINT_MAP() + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif +BEGIN_MSG_MAP(CSOActiveX) +#if defined __clang__ +#pragma clang diagnostic pop +#endif + CHAIN_MSG_MAP(CComControl<CSOActiveX>) + DEFAULT_REFLECTION_HANDLER() +END_MSG_MAP() +// Handler prototypes: +// LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); +// LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled); +// LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled); + + + +// IViewObjectEx + static DECLARE_VIEW_STATUS(VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE) + +// ISOActiveX +public: + + STDMETHOD(SetClientSite)( IOleClientSite* aClientSite ) override; + STDMETHOD(Invoke)( DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS* pDispParams, + VARIANT* pvarResult, + EXCEPINFO* pExcepInfo, + UINT* puArgErr) override; + STDMETHOD(Load) ( LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog ) override; + STDMETHOD(Load) ( LPSTREAM pStm ) override; + STDMETHOD(InitNew) () override; + HRESULT OnDrawAdvanced(ATL_DRAWINFO& di) override; + HRESULT OnDraw(ATL_DRAWINFO& di) override; + + HRESULT SetLayoutManagerProps(); + HRESULT CreateFrameOldWay( HWND hwnd, int width, int height ); + HRESULT GetUnoStruct( OLECHAR const * sStructName, CComPtr<IDispatch>& pdispResult ); + HRESULT LoadURLToFrame(); + HRESULT CallDispatchMethod( OLECHAR const * sUrl, CComVariant* sArgNames, CComVariant* sArgVal, unsigned int count ); + HRESULT CallLoadComponentFromURL1PBool( OLECHAR const * sUrl, OLECHAR const * sArgName, BOOL sArgVal ); + HRESULT GetUrlStruct( OLECHAR const * sUrl, CComPtr<IDispatch>& pdispUrl ); + HRESULT Cleanup(); + HRESULT TerminateOffice(); + HRESULT GetURL( const OLECHAR* url, + const OLECHAR* target ); + + void CallbackCreateXInputStream( CBindStatusCallback<CSOActiveX>* pbsc, BYTE* pBytes, DWORD dwSize ); + + + SOVersion GetVersionConnected(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/SOActiveX.rgs b/extensions/source/activex/SOActiveX.rgs new file mode 100644 index 000000000..d3814df3b --- /dev/null +++ b/extensions/source/activex/SOActiveX.rgs @@ -0,0 +1,33 @@ +HKCR +{ + so_activex.SOActiveX.1 = s 'SOActiveX Class' + { + CLSID = s '{67F2A879-82D5-4A6D-8CC5-FFB3C114B69D}' + } + so_activex.SOActiveX = s 'SOActiveX Class' + { + CLSID = s '{67F2A879-82D5-4A6D-8CC5-FFB3C114B69D}' + CurVer = s 'so_activex.SOActiveX.1' + } + NoRemove CLSID + { + ForceRemove {67F2A879-82D5-4A6D-8CC5-FFB3C114B69D} = s 'SOActiveX Class' + { + ProgID = s 'so_activex.SOActiveX.1' + VersionIndependentProgID = s 'so_activex.SOActiveX' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + ForceRemove 'Control' + ForceRemove 'ToolboxBitmap32' = s '%MODULE%, 101' + 'MiscStatus' = s '0' + { + '1' = s '131473' + } + 'TypeLib' = s '{61FA3F13-8061-4796-B055-3697ED28CB38}' + 'Version' = s '1.0' + } + } +} diff --git a/extensions/source/activex/SOComWindowPeer.cxx b/extensions/source/activex/SOComWindowPeer.cxx new file mode 100644 index 000000000..0a556466d --- /dev/null +++ b/extensions/source/activex/SOComWindowPeer.cxx @@ -0,0 +1,57 @@ +/* -*- 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 . + */ + +// SOComWindowPeer.cpp : Implementation of CHelpApp and DLL registration. + +#include <sal/config.h> + +#include <cstddef> + +#include "StdAfx2.h" +#include "SOComWindowPeer.h" +#include <sal/macros.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 + +COM_DECLSPEC_NOTHROW STDMETHODIMP SOComWindowPeer::InterfaceSupportsErrorInfo(REFIID riid) +{ + static const IID* arr[] = { + &IID_ISOComWindowPeer, + }; + + for (std::size_t i = 0; i < SAL_N_ELEMENTS(arr); i++) + { +#ifdef _MSC_VER + if (InlineIsEqualGUID(*arr[i], riid)) +#else + if (::ATL::InlineIsEqualGUID(*arr[i], riid)) +#endif + return S_OK; + } + return S_FALSE; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/SOComWindowPeer.h b/extensions/source/activex/SOComWindowPeer.h new file mode 100644 index 000000000..379ca767a --- /dev/null +++ b/extensions/source/activex/SOComWindowPeer.h @@ -0,0 +1,159 @@ +/* -*- 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 . + */ + +// SOComWindowPeer.h: Definition of the SOComWindowPeer class + +#pragma once + +#ifdef _MSC_VER +#pragma once +#endif + +#include "resource.h" +#include <ExDispID.h> +#include <ExDisp.h> +#include <shlguid.h> + +#include <atlctl.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 + +// SOComWindowPeer + +class SOComWindowPeer : + public IDispatchImpl<ISOComWindowPeer, &IID_ISOComWindowPeer, &LIBID_SO_ACTIVEXLib>, + public ISupportErrorInfo, + public CComObjectRoot, + public CComCoClass<SOComWindowPeer,&CLSID_SOComWindowPeer> +{ + HWND m_hwnd; +public: + SOComWindowPeer() : m_hwnd( nullptr ) {} + virtual ~SOComWindowPeer() { } + +BEGIN_COM_MAP(SOComWindowPeer) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(ISOComWindowPeer) + COM_INTERFACE_ENTRY(ISupportErrorInfo) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif +END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif +DECLARE_NOT_AGGREGATABLE(SOComWindowPeer) +// Remove the comment from the line above if you don't want your object to +// support aggregation. + +DECLARE_REGISTRY_RESOURCEID(IDR_SOCOMWINDOWPEER) + +// ISupportsErrorInfo + STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) override; + +// ISOComWindowPeer + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getWindowHandle( + /* [in] */ SAFEARRAY __RPC_FAR * /*procId*/, + /* [in] */ short /*s*/, + /* [retval][out] */ long __RPC_FAR *ret) override + { + *ret = HandleToLong( m_hwnd ); + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getToolkit( + /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *retVal) override + { + *retVal = nullptr; + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE setPointer( + /* [in] */ IDispatch __RPC_FAR* /*xPointer*/) override + { + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE setBackground( + /* [in] */ int /*nColor*/) override + { + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE invalidate( + /* [in] */ short /*__MIDL_0015*/) override + { + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE invalidateRect( + /* [in] */ IDispatch __RPC_FAR* /*aRect*/, + /* [in] */ short /*nFlags*/) override + { + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE dispose( void) override + { + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE addEventListener( + /* [in] */ IDispatch __RPC_FAR* /*xListener*/) override + { + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE removeEventListener( + /* [in] */ IDispatch __RPC_FAR* /*xListener*/) override + { + return S_OK; + } + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_Bridge_implementedInterfaces( + /* [retval][out] */ SAFEARRAY __RPC_FAR * __RPC_FAR *pVal) override + { + *pVal = SafeArrayCreateVector( VT_BSTR, 0, 2 ); + + if( !*pVal ) + return E_FAIL; + + LONG ix = 0; + CComBSTR aInterface( OLESTR( "com.sun.star.awt.XSystemDependentWindowPeer" ) ); + SafeArrayPutElement( *pVal, &ix, aInterface ); + + ix = 1; + aInterface = CComBSTR( OLESTR( "com.sun.star.awt.XWindowPeer" ) ); + SafeArrayPutElement( *pVal, &ix, aInterface ); + + return S_OK; + } + + void SetHWNDInternally( HWND hwnd ) { m_hwnd = hwnd; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/SOComWindowPeer.rgs b/extensions/source/activex/SOComWindowPeer.rgs new file mode 100644 index 000000000..42e985a31 --- /dev/null +++ b/extensions/source/activex/SOComWindowPeer.rgs @@ -0,0 +1,23 @@ +HKCR +{ + so_activex.SOComWindowPeer.1 = s 'SOComWindowPeer Class' + { + CLSID = s '{EE51BD3E-8BB6-4FB8-B319-F65B1BE3B21D}' + } + so_activex.SOComWindowPeer = s 'SOComWindowPeer Class' + { + CLSID = s '{EE51BD3E-8BB6-4FB8-B319-F65B1BE3B21D}' + } + NoRemove CLSID + { + ForceRemove {EE51BD3E-8BB6-4FB8-B319-F65B1BE3B21D} = s 'SOComWindowPeer Class' + { + ProgID = s 'so_activex.SOComWindowPeer.1' + VersionIndependentProgID = s 'so_activex.SOComWindowPeer' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'both' + } + } + } +} diff --git a/extensions/source/activex/SODispatchInterceptor.cxx b/extensions/source/activex/SODispatchInterceptor.cxx new file mode 100644 index 000000000..f40f62635 --- /dev/null +++ b/extensions/source/activex/SODispatchInterceptor.cxx @@ -0,0 +1,248 @@ +/* -*- 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 . + */ + +// SODispatchInterceptor.cpp : Implementation of CHelpApp and DLL registration. + +#include <sal/config.h> + +#include <cstddef> + +#include <stdio.h> +#include "StdAfx2.h" +#include "SOActiveX.h" +#include "SODispatchInterceptor.h" +#include "com_uno_helper.h" +#include <sal/macros.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 + +COM_DECLSPEC_NOTHROW STDMETHODIMP SODispatchInterceptor::InterfaceSupportsErrorInfo(REFIID riid) +{ + static const IID* arr[] = + { + &IID_ISODispatchInterceptor, + }; + + for (std::size_t i=0;i<SAL_N_ELEMENTS(arr);i++) + { +#ifdef _MSC_VER + if (InlineIsEqualGUID(*arr[i],riid)) +#else + if (::ATL::InlineIsEqualGUID(*arr[i],riid)) +#endif + return S_OK; + } + return S_FALSE; +} + +STDMETHODIMP SODispatchInterceptor::queryDispatch(IDispatch* aURL, BSTR aTargetFrameName, + long nSearchFlags, IDispatch** retVal) +{ + if ( !aURL || !retVal ) return E_FAIL; + + CComVariant aTargetUrl; + OLECHAR const * sURLMemberName = L"Complete"; + DISPID nURLID; + HRESULT hr = aURL->GetIDsOfNames( IID_NULL, const_cast<OLECHAR **>(&sURLMemberName), 1, LOCALE_USER_DEFAULT, &nURLID ); + if( !SUCCEEDED( hr ) ) return hr; + + hr = CComDispatchDriver::GetProperty( aURL, nURLID, &aTargetUrl ); + if( !SUCCEEDED( hr ) ) return hr; + + if( aTargetUrl.vt != VT_BSTR ) return E_FAIL; + + if (!wcsncmp(aTargetUrl.bstrVal, L".uno:OpenHyperlink", 18)) + { + CComQIPtr< IDispatch, &IID_IDispatch > pIDisp( this ); + if( pIDisp ) + { + this->AddRef(); + *retVal = pIDisp; + } + } + else + { + if( !m_xSlave ) + { + *retVal = nullptr; + return S_OK; + } + + CComVariant aResult; + CComVariant aArgs[3]; + aArgs[0] = CComVariant( nSearchFlags ); + aArgs[1] = CComVariant( aTargetFrameName ); + aArgs[2] = CComVariant( aURL ); + + hr = ExecuteFunc( m_xSlave, L"queryDispatch", aArgs, 3, &aResult ); + if( !SUCCEEDED( hr ) || aResult.vt != VT_DISPATCH || aResult.pdispVal == nullptr ) + { + *retVal = nullptr; + return S_OK; + } + + *retVal = aResult.pdispVal; + + CComQIPtr< IUnknown, &IID_IUnknown > pIUnk( *retVal ); + if( pIUnk ) + (*retVal)->AddRef(); + } + + return S_OK; +} + +STDMETHODIMP SODispatchInterceptor::queryDispatches(SAFEARRAY* aDescripts, SAFEARRAY** retVal) +{ + if ( !aDescripts || !retVal || SafeArrayGetDim( aDescripts ) != 1 ) + return E_FAIL; + + LONG nLB, nUB; + + HRESULT hr = SafeArrayGetLBound( aDescripts, 1, &nLB ); + if( !SUCCEEDED( hr ) ) return hr; + + hr = SafeArrayGetUBound( aDescripts, 1, &nUB ); + if( !SUCCEEDED( hr ) ) return hr; + if( nUB < nLB ) return E_FAIL; + + *retVal = SafeArrayCreateVector( VT_DISPATCH, 0, nUB - nLB ); + + for ( LONG ind = nLB; ind <= nUB; ind ++ ) + { + CComPtr<IDispatch> pElem; + SafeArrayGetElement( aDescripts, &ind, pElem ); + if( pElem ) + { + OLECHAR const * pMemberNames[3] = { L"FeatureURL", L"FrameName", L"SearchFlags" }; + CComVariant pValues[3]; + hr = GetPropertiesFromIDisp( pElem, pMemberNames, pValues, 3 ); + if( !SUCCEEDED( hr ) ) return hr; + if( pValues[0].vt != VT_DISPATCH || pValues[0].pdispVal == nullptr + || pValues[1].vt != VT_BSTR || pValues[2].vt != VT_I4 ) + return E_FAIL; + + CComPtr<IDispatch> aRes; + hr = queryDispatch( pValues[0].pdispVal, pValues[1].bstrVal, pValues[2].lVal, &aRes ); + SafeArrayPutElement( *retVal, &ind, aRes ); + } + } + + return S_OK; +} + + +STDMETHODIMP SODispatchInterceptor::dispatch(IDispatch* aURL, SAFEARRAY* aArgs) +{ + // get url from aURL + OLECHAR const * pUrlName = L"Complete"; + CComVariant pValue; + HRESULT hr = GetPropertiesFromIDisp( aURL, &pUrlName, &pValue, 1 ); + if( !SUCCEEDED( hr ) ) return hr; + if( pValue.vt != VT_BSTR || pValue.bstrVal == nullptr ) + return E_FAIL; + + if (!wcsncmp(pValue.bstrVal, L".uno:OpenHyperlink", 18)) + { + LONG nLB = 0, nUB = 0; + // long nDim = SafeArrayGetDim( aArgs ); + + hr = SafeArrayGetLBound( aArgs, 1, &nLB ); + if( !SUCCEEDED( hr ) ) return hr; + + hr = SafeArrayGetUBound( aArgs, 1, &nUB ); + if( !SUCCEEDED( hr ) ) return hr; + if( nUB < nLB ) return E_FAIL; + + for ( LONG ind = nLB; ind <= nUB; ind ++ ) + { + CComVariant pVarElem; + SafeArrayGetElement( aArgs, &ind, &pVarElem ); + if( pVarElem.vt == VT_DISPATCH && pVarElem.pdispVal != nullptr ) + { + OLECHAR const * pMemberNames[2] = { L"Name", L"Value" }; + CComVariant pValues[2]; + hr = GetPropertiesFromIDisp( pVarElem.pdispVal, pMemberNames, pValues, 2 ); + if( !SUCCEEDED( hr ) ) return hr; + + if( pValues[0].vt == VT_BSTR && pValues[1].vt == VT_BSTR ) + { + if (!wcsncmp(pValues[0].bstrVal, L"URL", 3)) + { + EnterCriticalSection( &mMutex ); + if( m_xParentControl ) + { + // call GetUrl to the browser instance + m_xParentControl->GetURL( pValues[1].bstrVal, L"_self" ); + } + LeaveCriticalSection( &mMutex ); + + break; + } + } + } + } + } + + return S_OK; +} + +STDMETHODIMP SODispatchInterceptor::addStatusListener(IDispatch* /*xControl*/, IDispatch* /*aURL*/) +{ + // not implemented + return S_OK; +} + +STDMETHODIMP SODispatchInterceptor::removeStatusListener(IDispatch* /*xControl*/, + IDispatch* /*aURL*/) +{ + // not implemented + return S_OK; +} + +STDMETHODIMP SODispatchInterceptor::getInterceptedURLs(SAFEARRAY** pVal) +{ + *pVal = SafeArrayCreateVector( VT_BSTR, 0, 3 ); + + if( !*pVal ) + return E_FAIL; + + LONG ix = 0; + CComBSTR aPattern( OLESTR( "ftp://*" ) ); + SafeArrayPutElement( *pVal, &ix, aPattern ); + + ix = 1; + aPattern = CComBSTR( OLESTR( "http://*" ) ); + SafeArrayPutElement( *pVal, &ix, aPattern ); + + ix = 2; + aPattern = CComBSTR( OLESTR( "file://*" ) ); + SafeArrayPutElement( *pVal, &ix, aPattern ); + + return S_OK; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/SODispatchInterceptor.h b/extensions/source/activex/SODispatchInterceptor.h new file mode 100644 index 000000000..3c0604348 --- /dev/null +++ b/extensions/source/activex/SODispatchInterceptor.h @@ -0,0 +1,175 @@ +/* -*- 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 . + */ + +// SODispatchInterceptor.h: Definition of the SODispatchInterceptor class + +#pragma once + +#ifdef _MSC_VER +#pragma once +#endif + +#include "resource.h" +#include <ExDispID.h> +#include <ExDisp.h> +#include <shlguid.h> + +#include <atlctl.h> + +#include <so_activex.h> + +class CSOActiveX; + + +// SODispatchInterceptor + +class SODispatchInterceptor : + public IDispatchImpl<ISODispatchInterceptor, &IID_ISODispatchInterceptor, &LIBID_SO_ACTIVEXLib>, + public ISupportErrorInfo, + public CComObjectRoot, + public CComCoClass<SODispatchInterceptor,&CLSID_SODispatchInterceptor> +{ + CComPtr<IDispatch> m_xMaster; + CComPtr<IDispatch> m_xSlave; + CSOActiveX* m_xParentControl; + CRITICAL_SECTION mMutex; +public: + SODispatchInterceptor() : m_xParentControl( nullptr ) { InitializeCriticalSection(&mMutex); } + virtual ~SODispatchInterceptor() { ATLASSERT( !m_xParentControl ); DeleteCriticalSection(&mMutex); } + +BEGIN_COM_MAP(SODispatchInterceptor) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(ISODispatchInterceptor) + COM_INTERFACE_ENTRY(ISupportErrorInfo) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif +END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif +DECLARE_NOT_AGGREGATABLE(SODispatchInterceptor) +// Remove the comment from the line above if you don't want your object to +// support aggregation. + +DECLARE_REGISTRY_RESOURCEID(IDR_SODISPATCHINTERCEPTOR) + + void SetParent( CSOActiveX* pParent ) + { + ATLASSERT( !m_xParentControl ); + EnterCriticalSection( &mMutex ); + m_xParentControl = pParent; + LeaveCriticalSection( &mMutex ); + } + + void ClearParent() + { + EnterCriticalSection( &mMutex ); + m_xParentControl = nullptr; + LeaveCriticalSection( &mMutex ); + } + +// ISupportsErrorInfo + STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) override; + +// ISODispatchInterceptor + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getSlaveDispatchProvider( + /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *retVal) override + { + *retVal = m_xSlave; + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE setSlaveDispatchProvider( + /* [in] */ IDispatch __RPC_FAR *xNewDispatchProvider) override + { + m_xSlave = xNewDispatchProvider; + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getMasterDispatchProvider( + /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *retVal) override + { + *retVal = m_xMaster; + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE setMasterDispatchProvider( + /* [in] */ IDispatch __RPC_FAR *xNewSupplier) override + { + m_xMaster = xNewSupplier; + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE queryDispatch( + /* [in] */ IDispatch __RPC_FAR *aURL, + /* [in] */ BSTR aTargetFrameName, + /* [in] */ long nSearchFlags, + /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *retVal) override; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE queryDispatches( + /* [in] */ SAFEARRAY __RPC_FAR * aDescripts, + /* [retval][out] */ SAFEARRAY __RPC_FAR * __RPC_FAR *retVal) override; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE dispatch( + /* [in] */ IDispatch __RPC_FAR *aURL, + /* [in] */ SAFEARRAY __RPC_FAR * aArgs) override; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE addStatusListener( + /* [in] */ IDispatch __RPC_FAR *xControl, + /* [in] */ IDispatch __RPC_FAR *aURL) override; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE removeStatusListener( + /* [in] */ IDispatch __RPC_FAR *xControl, + /* [in] */ IDispatch __RPC_FAR *aURL) override; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getInterceptedURLs( + /* [retval][out] */ SAFEARRAY __RPC_FAR * __RPC_FAR *pVal) override; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_Bridge_implementedInterfaces( + /* [retval][out] */ SAFEARRAY __RPC_FAR * __RPC_FAR *pVal) override + { + *pVal = SafeArrayCreateVector( VT_BSTR, 0, 4 ); + + if( !*pVal ) + return E_FAIL; + + LONG ix = 0; + CComBSTR aInterface( OLESTR( "com.sun.star.frame.XDispatchProviderInterceptor" ) ); + SafeArrayPutElement( *pVal, &ix, aInterface ); + + ix = 1; + aInterface = CComBSTR( OLESTR( "com.sun.star.frame.XDispatchProvider" ) ); + SafeArrayPutElement( *pVal, &ix, aInterface ); + + ix = 2; + aInterface = CComBSTR( OLESTR( "com.sun.star.frame.XDispatch" ) ); + SafeArrayPutElement( *pVal, &ix, aInterface ); + + ix = 3; + aInterface = CComBSTR( OLESTR( "com.sun.star.frame.XInterceptorInfo" ) ); + SafeArrayPutElement( *pVal, &ix, aInterface ); + + return S_OK; + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/SODispatchInterceptor.rgs b/extensions/source/activex/SODispatchInterceptor.rgs new file mode 100644 index 000000000..19fe0b5f0 --- /dev/null +++ b/extensions/source/activex/SODispatchInterceptor.rgs @@ -0,0 +1,23 @@ +HKCR +{ + so_activex.SODispatchInterceptor.1 = s 'SODispatchInterceptor Class' + { + CLSID = s '{C5D6D568-57DA-4D6C-819A-451CB565E682}' + } + so_activex.SODispatchInterceptor = s 'SODispatchInterceptor Class' + { + CLSID = s '{C5D6D568-57DA-4D6C-819A-451CB565E682}' + } + NoRemove CLSID + { + ForceRemove {C5D6D568-57DA-4D6C-819A-451CB565E682} = s 'SODispatchInterceptor Class' + { + ProgID = s 'so_activex.SODispatchInterceptor.1' + VersionIndependentProgID = s 'so_activex.SODispatchInterceptor' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'both' + } + } + } +} diff --git a/extensions/source/activex/StdAfx2.cxx b/extensions/source/activex/StdAfx2.cxx new file mode 100644 index 000000000..c2df5c5c0 --- /dev/null +++ b/extensions/source/activex/StdAfx2.cxx @@ -0,0 +1,30 @@ +/* -*- 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 . + */ + +// stdafx1.cpp : source file that includes just the standard includes +// stdafx1.pch will be the pre-compiled header +// stdafx1.obj will contain the pre-compiled type information + +#include "StdAfx2.h" + +#ifdef _ATL_STATIC_REGISTRY +#include <statreg.h> +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/StdAfx2.h b/extensions/source/activex/StdAfx2.h new file mode 100644 index 000000000..56bd75b8a --- /dev/null +++ b/extensions/source/activex/StdAfx2.h @@ -0,0 +1,68 @@ +/* -*- 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 . + */ + +// stdafx1.h : include file for standard system include files, +// or project specific include files that are used frequently, +// but are changed infrequently + +#pragma once + +#define STRICT +#define _ATL_APARTMENT_THREADED +#define _ATL_STATIC_REGISTRY + +#pragma warning(push) +// local variable is initialized but not referenced - in atlctl.h +#pragma warning(disable : 4189) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wall" +#pragma clang diagnostic ignored "-Wattributes" +#pragma clang diagnostic ignored "-Wdelete-incomplete" +#pragma clang diagnostic ignored "-Wdynamic-class-memaccess" +#pragma clang diagnostic ignored "-Wint-to-pointer-cast" +#pragma clang diagnostic ignored "-Winvalid-noreturn" +#pragma clang diagnostic ignored "-Wmicrosoft" +#pragma clang diagnostic ignored "-Wmissing-field-initializers" +#pragma clang diagnostic ignored "-Wnon-pod-varargs" +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#pragma clang diagnostic ignored "-Wnonportable-include-path" +#pragma clang diagnostic ignored "-Wsequence-point" +#pragma clang diagnostic ignored "-Wsign-compare" +#pragma clang diagnostic ignored "-Wtypename-missing" +#endif + +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#include <atlbase.h> + +//You may derive a class from CComModule and use it if you want to override +//something, but do not change the name of _Module +extern CComModule _Module; +#include <atlcom.h> +#include <atlctl.h> + +#if defined __clang__ +#pragma clang diagnostic pop +#endif +#pragma warning(pop) + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/com_uno_helper.h b/extensions/source/activex/com_uno_helper.h new file mode 100644 index 000000000..89aa0a7d1 --- /dev/null +++ b/extensions/source/activex/com_uno_helper.h @@ -0,0 +1,44 @@ +/* -*- 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 . + */ + +#include "StdAfx2.h" + +HRESULT ExecuteFunc( IDispatch* idispUnoObject, + OLECHAR const * sFuncName, + CComVariant* params, + unsigned int count, + CComVariant* pResult ); + +HRESULT GetIDispByFunc( IDispatch* idispUnoObject, + OLECHAR* sFuncName, + CComVariant* params, + unsigned int count, + CComPtr<IDispatch>& pdispResult ); + +HRESULT PutPropertiesToIDisp( IDispatch* pdispObject, + OLECHAR** sMemberNames, + CComVariant* pVariant, + unsigned int count ); + +HRESULT GetPropertiesFromIDisp( IDispatch* pdispObject, + OLECHAR const ** sMemberNames, + CComVariant* pVariant, + unsigned int count ); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/example.html b/extensions/source/activex/example.html new file mode 100644 index 000000000..96e764c8f --- /dev/null +++ b/extensions/source/activex/example.html @@ -0,0 +1,43 @@ +<!-- + * 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 . +--> +<HTML> +<HEAD> +<TITLE>Document Title</TITLE> +</HEAD> +<BODY> + +<center> +First you should edit the example.html file!!! +</center> +<center> +<!-- Please edit CODEBASE parameter --> +<!-- In case ActiveX control is already registered the parameter can be removed --> +<OBJECT CLASSID="clsid:67F2A879-82D5-4A6D-8CC5-FFB3C114B69D" width="500" height="500" + CODEBASE="..\..\..\WINexample.out\bin\so_activex.dll"> +<!-- Full URL to a document + <PARAM NAME="src" VALUE="file:///d:/example.sxw"> +--> +<!-- Just view the document, do not edit + <PARAM NAME="readonly" VALUE="true"> +--> +</OBJECT> + +</center> + +</BODY> +</HTML> diff --git a/extensions/source/activex/resource.h b/extensions/source/activex/resource.h new file mode 100644 index 000000000..b7a77a5c9 --- /dev/null +++ b/extensions/source/activex/resource.h @@ -0,0 +1,46 @@ +/* -*- 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 . + */ + +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by so_activex.rc + +#define IDS_PROJNAME 100 +#define IDB_SOACTIVEX 101 +#define IDR_SOACTIVEX 102 +#define IDB_SOCOMWINDOWPEER 103 +#define IDR_SOCOMWINDOWPEER 104 +#define IDB_SODISPATCHINTERCEPTOR 105 +#define IDR_SODISPATCHINTERCEPTOR 106 +#define IDB_SODOCUMENTEVENTLISTENER 107 +#define IDR_SODOCUMENTEVENTLISTENER 108 + + +// Next default values for new objects + +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 201 +#define _APS_NEXT_COMMAND_VALUE 32768 +#define _APS_NEXT_CONTROL_VALUE 201 +#define _APS_NEXT_SYMED_VALUE 107 +#endif +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/so_activex.cxx b/extensions/source/activex/so_activex.cxx new file mode 100644 index 000000000..70682a416 --- /dev/null +++ b/extensions/source/activex/so_activex.cxx @@ -0,0 +1,774 @@ +/* -*- 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 . + */ + +// so_activex.cpp : Implementation of DLL Exports. + +// Note: Proxy/Stub Information +// To build a separate proxy/stub DLL, +// run nmake -f so_activexps.mk in the project directory. + +#include <stdio.h> +#include "StdAfx2.h" +#include "resource.h" +#include <initguid.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 + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra-tokens" + // "#endif !_MIDL_USE_GUIDDEF_" in midl-generated code +#endif +#include <so_activex_i.c> +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +#include "SOActiveX.h" + +#include <comphelper\documentconstants.hxx> +#include <sal/types.h> +#include <exception> + +CComModule _Module; + +BEGIN_OBJECT_MAP(ObjectMap) +OBJECT_ENTRY(CLSID_SOActiveX, CSOActiveX) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmissing-field-initializers" +#endif +END_OBJECT_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +#define X64_LIB_NAME L"so_activex_x64.dll" +#define X32_LIB_NAME L"so_activex.dll" + +const REGSAM n64KeyAccess = KEY_ALL_ACCESS | KEY_WOW64_64KEY; +const REGSAM n32KeyAccess = KEY_ALL_ACCESS; + +#ifdef _AMD64_ +const bool bX64 = true; +#define REG_DELETE_KEY_A( key, aPath, nKeyAccess ) RegDeleteKeyExA( key, aPath, nKeyAccess, 0 ) +#else +const bool bX64 = false; +#define REG_DELETE_KEY_A( key, aPath, nKeyAccess ) RegDeleteKeyA( key, aPath ) +#endif + +// DLL Entry Point + +extern "C" +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + _Module.Init(ObjectMap, hInstance, &LIBID_SO_ACTIVEXLib); + DisableThreadLibraryCalls(hInstance); + } + else if (dwReason == DLL_PROCESS_DETACH) + _Module.Term(); + return TRUE; // ok +} + + +// Used to determine whether the DLL can be unloaded by OLE + +STDAPI DllCanUnloadNow() +{ + return (_Module.GetLockCount()==0) ? S_OK : S_FALSE; +} + + +// Returns a class factory to create an object of the requested type + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + return _Module.GetClassObject(rclsid, riid, ppv); +} + + +// DllRegisterServer - Adds entries to the system registry + +namespace +{ +// Wraps an updatable Win32 error; keeps first incoming error. +// Ctor defines if upd will throw std::exception on error or +// return false. +class Status +{ +public: + explicit Status(bool bTrow) + : m_bThrow(bTrow) + { + } + // used to check success of an operation, and update the status if it's still ERROR_SUCCESS + bool upd(LSTATUS nNewStatus) + { + if (m_nStatus == ERROR_SUCCESS) + m_nStatus = nNewStatus; + if (m_bThrow && nNewStatus != ERROR_SUCCESS) + throw std::exception(); + return nNewStatus == ERROR_SUCCESS; + }; + LSTATUS get() { return m_nStatus; } + operator bool() { return m_nStatus == ERROR_SUCCESS; } + +private: + LSTATUS m_nStatus = ERROR_SUCCESS; + const bool m_bThrow; +}; + +class HRegKey +{ +public: + ~HRegKey() + { + if (m_hkey) + RegCloseKey(m_hkey); + } + PHKEY operator&() { return &m_hkey; } + operator HKEY() { return m_hkey; } + +private: + HKEY m_hkey = nullptr; +}; +} + +// for now database component and chart are always installed +#define SUPPORTED_EXT_NUM 30 +const char* const aFileExt[] = { ".vor", + ".sds", ".sda", ".sdd", ".sdp", ".sdc", ".sdw", ".smf", + ".stw", ".stc", ".sti", ".std", + ".sxw", ".sxc", ".sxi", ".sxd", ".sxg", ".sxm", + ".ott", ".otg", ".otp", ".ots", ".otf", + ".odt", ".oth", ".odm", ".odg", ".odp", ".ods", ".odf"}; +const sal_Unicode* const aMimeType[] = { + u"application/vnd.stardivision.writer", + + u"application/vnd.stardivision.chart", + u"application/vnd.stardivision.draw", + u"application/vnd.stardivision.impress", + u"application/vnd.stardivision.impress-packed", + u"application/vnd.stardivision.calc", + u"application/vnd.stardivision.writer", + u"application/vnd.stardivision.math", + + MIMETYPE_VND_SUN_XML_WRITER_TEMPLATE_ASCII.getStr(), + MIMETYPE_VND_SUN_XML_CALC_TEMPLATE_ASCII.getStr(), + MIMETYPE_VND_SUN_XML_IMPRESS_TEMPLATE_ASCII.getStr(), + MIMETYPE_VND_SUN_XML_DRAW_TEMPLATE_ASCII.getStr(), + + MIMETYPE_VND_SUN_XML_WRITER_ASCII.getStr(), + MIMETYPE_VND_SUN_XML_CALC_ASCII.getStr(), + MIMETYPE_VND_SUN_XML_IMPRESS_ASCII.getStr(), + MIMETYPE_VND_SUN_XML_DRAW_ASCII.getStr(), + MIMETYPE_VND_SUN_XML_WRITER_GLOBAL_ASCII.getStr(), + MIMETYPE_VND_SUN_XML_MATH_ASCII.getStr(), + + MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_TEMPLATE_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE_ASCII.getStr(), + + MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII.getStr() }; + +const int nForModes[] = { 16, + 1, 2, 4, 4, 8, 16, 32, + 16, 8, 4, 2, + 16, 8, 4, 2, 16, 32, + 16, 2, 4, 8, 32, + 16, 16, 16, 2, 4, 8, 32 }; + +const char* const aClassID = "{67F2A879-82D5-4A6D-8CC5-FFB3C114B69D}"; +const char* const aTypeLib = "{61FA3F13-8061-4796-B055-3697ED28CB38}"; + +// ISOComWindowPeer interface information +const char* const aInterIDWinPeer = "{BF5D10F3-8A10-4A0B-B150-2B6AA2D7E118}"; +const char* const aProxyStubWinPeer = "{00020424-0000-0000-C000-000000000046}"; + +// ISODispatchInterceptor interface information +const char* const aInterIDDispInt = "{9337694C-B27D-4384-95A4-9D8E0EABC9E5}"; +const char* const aProxyStubDispInt = "{00020424-0000-0000-C000-000000000046}"; + +// ISOActionsApproval interface information +const char* const aInterIDActApprove = "{029E9F1E-2B3F-4297-9160-8197DE7ED54F}"; +const char* const aProxyStubActApprove = "{00020424-0000-0000-C000-000000000046}"; + +// The following prefix is required for HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER ( not for HKEY_CLASSES_ROOT ) +const char* const aLocalPrefix = "Software\\Classes\\"; + +static LSTATUS createKey( HKEY hkey, + const char* aKeyToCreate, + REGSAM nKeyAccess, + const char* aValue = nullptr, + const char* aChildName = nullptr, + const char* aChildValue = nullptr ) +{ + Status s(false); // no throw + HRegKey hkey1; + if (s.upd(RegCreateKeyExA(hkey, aKeyToCreate, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey1, nullptr))) + { + if (aValue) + s.upd(RegSetValueExA(hkey1, "", 0, REG_SZ, reinterpret_cast<const BYTE*>(aValue), + sal::static_int_cast<DWORD>(strlen(aValue)))); + if (aChildName) + s.upd(RegSetValueExA(hkey1, aChildName, 0, REG_SZ, + reinterpret_cast<const BYTE*>(aChildValue), + sal::static_int_cast<DWORD>(strlen(aChildValue)))); + } + return s.get(); +} + +static LSTATUS createKey(HKEY hkey, + const wchar_t* aKeyToCreate, + REGSAM nKeyAccess, + const wchar_t* aValue = nullptr, + const wchar_t* aChildName = nullptr, + const wchar_t* aChildValue = nullptr ) +{ + Status s(false); // no throw + HRegKey hkey1; + if (s.upd(RegCreateKeyExW(hkey, aKeyToCreate, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey1, nullptr))) + { + if (aValue) + s.upd(RegSetValueExW(hkey1, L"", 0, REG_SZ, reinterpret_cast<const BYTE*>(aValue), + sal::static_int_cast<DWORD>(wcslen(aValue) * sizeof(wchar_t)))); + if (aChildName) + s.upd(RegSetValueExW( + hkey1, aChildName, 0, REG_SZ, reinterpret_cast<const BYTE*>(aChildValue), + sal::static_int_cast<DWORD>(wcslen(aChildValue) * sizeof(wchar_t)))); + } + return s.get(); +} + +EXTERN_C __declspec(dllexport) HRESULT STDAPICALLTYPE DllUnregisterServerNative( int nMode, BOOL bForAllUsers, BOOL bFor64Bit ); +static HRESULT DllRegisterServerNative_Impl( int nMode, bool bForAllUsers, REGSAM nKeyAccess, const wchar_t* pProgramPath, const wchar_t* pLibName ) +{ + char aSubKey[513]; + int ind; + const char* aPrefix = aLocalPrefix; // bForAllUsers ? "" : aLocalPrefix; + + // In case SO7 is installed for this user he can have local registry entries that will prevent him from + // using SO8 ActiveX control. The fix is just to clean up the local entries related to ActiveX control. + // Unfortunately it can be done only for the user who installs the office. + if ( bForAllUsers ) + DllUnregisterServerNative( nMode, false, false ); + + Status s(true); // throw + try + { + if (pProgramPath && wcslen(pProgramPath) < 1024) + { + wchar_t pActiveXPath[1124]; + wchar_t pActiveXPath101[1124]; + + swprintf(pActiveXPath, L"%s\\%s", pProgramPath, pLibName); + swprintf(pActiveXPath101, L"%s\\%s, 101", pProgramPath, pLibName); + + { + wsprintfA(aSubKey, "%sCLSID\\%s", aPrefix, aClassID); + HRegKey hkey; + s.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr)); + s.upd(RegSetValueExA(hkey, "", 0, REG_SZ, + reinterpret_cast<const BYTE*>("SOActiveX Class"), 17)); + s.upd(createKey(hkey, "Control", nKeyAccess)); + s.upd(createKey(hkey, "EnableFullPage", nKeyAccess)); + s.upd(createKey(hkey, L"InprocServer32", nKeyAccess, pActiveXPath, + L"ThreadingModel", L"Apartment")); + s.upd(createKey(hkey, "MiscStatus", nKeyAccess, "0")); + s.upd(createKey(hkey, "MiscStatus\\1", nKeyAccess, "131473")); + s.upd(createKey(hkey, "ProgID", nKeyAccess, "so_activex.SOActiveX.1")); + s.upd(createKey(hkey, "Programmable", nKeyAccess)); + s.upd(createKey(hkey, L"ToolboxBitmap32", nKeyAccess, pActiveXPath101)); + s.upd(createKey(hkey, "TypeLib", nKeyAccess, aTypeLib)); + s.upd(createKey(hkey, "Version", nKeyAccess, "1.0")); + s.upd(createKey(hkey, "VersionIndependentProgID", nKeyAccess, + "so_activex.SOActiveX")); + } + { + HRegKey hkey; + s.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aPrefix, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr)); + s.upd(createKey(hkey, "so_activex.SOActiveX", nKeyAccess, "SOActiveX Class")); + { + HRegKey hkey1; + s.upd(RegCreateKeyExA(hkey, "so_activex.SOActiveX", 0, nullptr, + REG_OPTION_NON_VOLATILE, nKeyAccess, nullptr, &hkey1, + nullptr)); + s.upd(createKey(hkey1, "CLSID", nKeyAccess, aClassID)); + s.upd(createKey(hkey1, "CurVer", nKeyAccess, "so_activex.SOActiveX.1")); + } + s.upd(createKey(hkey, "so_activex.SOActiveX.1", nKeyAccess, "SOActiveX Class")); + { + HRegKey hkey1; + s.upd(RegCreateKeyExA(hkey, "so_activex.SOActiveX.1", 0, nullptr, + REG_OPTION_NON_VOLATILE, nKeyAccess, nullptr, &hkey1, + nullptr)); + s.upd(createKey(hkey1, "CLSID", nKeyAccess, aClassID)); + } + { + HRegKey hkey1; + s.upd(RegCreateKeyExA(hkey, "TypeLib", 0, nullptr, REG_OPTION_NON_VOLATILE, + nKeyAccess, nullptr, &hkey1, nullptr)); + { + HRegKey hkey2; + s.upd(RegCreateKeyExA(hkey1, aTypeLib, 0, nullptr, REG_OPTION_NON_VOLATILE, + nKeyAccess, nullptr, &hkey2, nullptr)); + s.upd(createKey(hkey2, "1.0", nKeyAccess, "wrap_activex 1.0 Type Library")); + { + HRegKey hkey3; + s.upd(RegCreateKeyExA(hkey2, "1.0", 0, nullptr, REG_OPTION_NON_VOLATILE, + nKeyAccess, nullptr, &hkey3, nullptr)); + { + HRegKey hkey4; + s.upd(RegCreateKeyExA(hkey3, "0", 0, nullptr, + REG_OPTION_NON_VOLATILE, nKeyAccess, nullptr, + &hkey4, nullptr)); + s.upd(createKey(hkey4, L"win32", nKeyAccess, pActiveXPath)); + } + s.upd(createKey(hkey3, "FLAGS", nKeyAccess, "0")); + s.upd(createKey(hkey3, L"HELPDIR", nKeyAccess, pProgramPath)); + } + } + } + { + HRegKey hkey1; + s.upd(RegCreateKeyExA(hkey, "Interface", 0, nullptr, REG_OPTION_NON_VOLATILE, + nKeyAccess, nullptr, &hkey1, nullptr)); + s.upd(createKey(hkey1, aInterIDWinPeer, nKeyAccess, "ISOComWindowPeer")); + { + HRegKey hkey2; + s.upd(RegCreateKeyExA(hkey1, aInterIDWinPeer, 0, nullptr, + REG_OPTION_NON_VOLATILE, nKeyAccess, nullptr, &hkey2, + nullptr)); + s.upd(createKey(hkey2, "ProxyStubClsid", nKeyAccess, aProxyStubWinPeer)); + s.upd(createKey(hkey2, "ProxyStubClsid32", nKeyAccess, aProxyStubWinPeer)); + s.upd(createKey(hkey2, "TypeLib", nKeyAccess, aTypeLib, "Version", "1.0")); + } + s.upd(createKey(hkey1, aInterIDActApprove, nKeyAccess, "ISOActionsApproval")); + { + HRegKey hkey2; + s.upd(RegCreateKeyExA(hkey1, aInterIDActApprove, 0, nullptr, + REG_OPTION_NON_VOLATILE, nKeyAccess, nullptr, &hkey2, + nullptr)); + s.upd(createKey(hkey2, "ProxyStubClsid", nKeyAccess, aProxyStubActApprove)); + s.upd( + createKey(hkey2, "ProxyStubClsid32", nKeyAccess, aProxyStubActApprove)); + s.upd(createKey(hkey2, "TypeLib", nKeyAccess, aTypeLib, "Version", "1.0")); + } + s.upd(createKey(hkey1, aInterIDDispInt, nKeyAccess, "ISODispatchInterceptor")); + { + HRegKey hkey2; + s.upd(RegCreateKeyExA(hkey1, aInterIDDispInt, 0, nullptr, + REG_OPTION_NON_VOLATILE, nKeyAccess, nullptr, &hkey2, + nullptr)); + s.upd(createKey(hkey2, "ProxyStubClsid", nKeyAccess, aProxyStubDispInt)); + s.upd(createKey(hkey2, "ProxyStubClsid32", nKeyAccess, aProxyStubDispInt)); + s.upd(createKey(hkey2, "TypeLib", nKeyAccess, aTypeLib, "Version", "1.0")); + } + } + } + } + + for (ind = 0; ind < SUPPORTED_EXT_NUM; ind++) + { + if (nForModes[ind] & nMode) + { + wsprintfA(aSubKey, "%sMIME\\DataBase\\Content Type\\%ls", aPrefix, aMimeType[ind]); + HRegKey hkey; + s.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr)); + s.upd(RegSetValueExA(hkey, "CLSID", 0, REG_SZ, + reinterpret_cast<const BYTE*>(aClassID), + sal::static_int_cast<DWORD>(strlen(aClassID)))); + } + } + + { + wsprintfA(aSubKey, "%sCLSID\\%s", aPrefix, aClassID); + HRegKey hkey; + s.upd(RegOpenKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, 0, + nKeyAccess, &hkey)); + for (ind = 0; ind < SUPPORTED_EXT_NUM; ind++) + { + wsprintfA(aSubKey, "EnableFullPage\\%s", aFileExt[ind]); + HRegKey hkey1; + s.upd(RegCreateKeyExA(hkey, aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, + nKeyAccess, nullptr, &hkey1, nullptr)); + } + } + } + catch (const std::exception&) {} + + return HRESULT_FROM_WIN32(s.get()); +} + +EXTERN_C __declspec(dllexport) HRESULT STDAPICALLTYPE DllRegisterServerNative( int nMode, BOOL bForAllUsers, BOOL bFor64Bit, const wchar_t* pProgramPath ) +{ + HRESULT hr = S_OK; + if ( bFor64Bit ) + hr = DllRegisterServerNative_Impl( nMode, bForAllUsers, n64KeyAccess, pProgramPath, X64_LIB_NAME ); + + if ( SUCCEEDED( hr ) ) + hr = DllRegisterServerNative_Impl( nMode, bForAllUsers, n32KeyAccess, pProgramPath, X32_LIB_NAME ); + + return hr; +} + + +// DllUnregisterServer - Removes entries from the system registry +static HRESULT DeleteKeyTree( HKEY hkey, const char* pPath, REGSAM nKeyAccess ) +{ + char pSubKeyName[256]; + // first delete the subkeys + while (true) + { + HRegKey hkey1; + if (ERROR_SUCCESS != RegOpenKeyExA(hkey, pPath, 0, nKeyAccess, &hkey1) + || ERROR_SUCCESS != RegEnumKeyA(hkey1, 0, pSubKeyName, 256) + || ERROR_SUCCESS != DeleteKeyTree(hkey1, pSubKeyName, nKeyAccess)) + break; + } + + // delete the key itself + return REG_DELETE_KEY_A( hkey, pPath, nKeyAccess & ( KEY_WOW64_64KEY | KEY_WOW64_32KEY ) ); +} + +static HRESULT DllUnregisterServerNative_Impl( int nMode, bool bForAllUsers, REGSAM nKeyAccess ) +{ + char aSubKey[513]; + const char* aPrefix = aLocalPrefix; // bForAllUsers ? "" : aLocalPrefix; + + Status s(false); // no throw + for( int ind = 0; ind < SUPPORTED_EXT_NUM; ind++ ) + { + if( nForModes[ind] & nMode ) + { + DWORD nSubKeys = 0, nValues = 0; + wsprintfA(aSubKey, "%sMIME\\DataBase\\Content Type\\%ls", aPrefix, aMimeType[ind]); + Status s1(false); // no throw + { + HRegKey hkey; + if (s1.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr))) + { + s1.upd(RegDeleteValueA(hkey, "CLSID")); + s1.upd(RegQueryInfoKeyA(hkey, nullptr, nullptr, nullptr, &nSubKeys, nullptr, + nullptr, &nValues, nullptr, nullptr, nullptr, nullptr)); + } + } + if (s1 && !nSubKeys && !nValues) + DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess); + s.upd(s1.get()); + + wsprintfA(aSubKey, "%s%s", aPrefix, aFileExt[ind]); + Status s2(false); // no throw + { + HRegKey hkey; + if (s2.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr))) + { + s2.upd(RegQueryInfoKeyA(hkey, nullptr, nullptr, nullptr, &nSubKeys, nullptr, + nullptr, &nValues, nullptr, nullptr, nullptr, nullptr)); + } + } + if (s2 && !nSubKeys && !nValues) + DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess); + s.upd(s2.get()); + } + } + + wsprintfA(aSubKey, "%sCLSID\\%s", aPrefix, aClassID); + s.upd(DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess)); + + wsprintfA(aSubKey, "%sso_activex.SOActiveX", aPrefix); + s.upd(DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess)); + + wsprintfA(aSubKey, "%sso_activex.SOActiveX.1", aPrefix); + s.upd(DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess)); + + wsprintfA(aSubKey, "%s\\TypeLib\\%s", aPrefix, aTypeLib); + s.upd(DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess)); + + wsprintfA(aSubKey, "%s\\Interface\\%s", aPrefix, aInterIDWinPeer); + s.upd(DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess)); + + wsprintfA(aSubKey, "%s\\Interface\\%s", aPrefix, aInterIDDispInt); + s.upd(DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess)); + + wsprintfA(aSubKey, "%s\\Interface\\%s", aPrefix, aInterIDActApprove); + s.upd(DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess)); + + return HRESULT_FROM_WIN32(s.get()); +} + +STDAPI DllUnregisterServerNative( int nMode, BOOL bForAllUsers, BOOL bFor64Bit ) +{ + HRESULT hr = DllUnregisterServerNative_Impl( nMode, bForAllUsers, n32KeyAccess ); + if ( SUCCEEDED( hr ) && bFor64Bit ) + hr = DllUnregisterServerNative_Impl( nMode, bForAllUsers, n64KeyAccess ); + + return hr; +} + + +// DllRegisterServerDoc - Adds entries to the system registry + +#define SUPPORTED_MSEXT_NUM 7 +const char* const aMSFileExt[] = { ".dot", ".doc", ".xlt", ".xls", ".pot", ".ppt", ".pps" }; +const char* const aMSMimeType[] = { "application/msword", + "application/msword", + "application/vnd.ms-excel", + "application/vnd.ms-excel", + "application/vnd.ms-powerpoint", + "application/vnd.ms-powerpoint", + "application/vnd.ms-powerpoint" }; +const int nForMSModes[] = { 1, 1, 2, 2, 4, 4, 4 }; + +EXTERN_C __declspec(dllexport) HRESULT STDAPICALLTYPE DllUnregisterServerDoc( int nMode, BOOL bForAllUsers, BOOL bFor64Bit ); +static HRESULT DllRegisterServerDoc_Impl( int nMode, bool bForAllUsers, REGSAM nKeyAccess ) +{ + char aSubKey[513]; + int ind; + const char* aPrefix = aLocalPrefix; // bForAllUsers ? "" : aLocalPrefix; + + // In case SO7 is installed for this user he can have local registry entries that will prevent him from + // using SO8 ActiveX control. The fix is just to clean up the local entries related to ActiveX control. + // Unfortunately it can be done only for the user who installs the office. + if ( bForAllUsers ) + DllUnregisterServerDoc( nMode, false, false ); + + Status s(true); // throw + try + { + for (ind = 0; ind < SUPPORTED_MSEXT_NUM; ind++) + { + if (nForMSModes[ind] & nMode) + { + { + wsprintfA(aSubKey, "%sMIME\\DataBase\\Content Type\\%s", aPrefix, + aMSMimeType[ind]); + HRegKey hkey; + s.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr)); + s.upd(RegSetValueExA(hkey, "Extension", 0, REG_SZ, + reinterpret_cast<const BYTE*>(aMSFileExt[ind]), + sal::static_int_cast<DWORD>(strlen(aMSFileExt[ind])))); + s.upd(RegSetValueExA(hkey, "CLSID", 0, REG_SZ, + reinterpret_cast<const BYTE*>(aClassID), + sal::static_int_cast<DWORD>(strlen(aClassID)))); + } + { + wsprintfA(aSubKey, "%s%s", aPrefix, aMSFileExt[ind]); + HRegKey hkey; + s.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr)); + s.upd(RegSetValueExA(hkey, "Content Type", 0, REG_SZ, + reinterpret_cast<const BYTE*>(aMSMimeType[ind]), + sal::static_int_cast<DWORD>(strlen(aMSMimeType[ind])))); + } + } + } + + wsprintfA(aSubKey, "%sCLSID\\%s", aPrefix, aClassID); + HRegKey hkey; + s.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, 0, + nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, nullptr, &hkey, + nullptr)); + s.upd(createKey(hkey, "EnableFullPage", nKeyAccess)); + for (ind = 0; ind < SUPPORTED_MSEXT_NUM; ind++) + { + if (nForMSModes[ind] & nMode) + { + wsprintfA(aSubKey, "EnableFullPage\\%s", aMSFileExt[ind]); + HRegKey hkey1; + s.upd(RegCreateKeyExA(hkey, aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, + nKeyAccess, nullptr, &hkey1, nullptr)); + } + } + } + catch (const std::exception&) {} + + return HRESULT_FROM_WIN32(s.get()); +} + +EXTERN_C __declspec(dllexport) HRESULT STDAPICALLTYPE DllRegisterServerDoc( int nMode, BOOL bForAllUsers, BOOL bFor64Bit ) +{ + HRESULT hr = S_OK; + if ( bFor64Bit ) + hr = DllRegisterServerDoc_Impl( nMode, bForAllUsers, n64KeyAccess ); + + if ( SUCCEEDED( hr ) ) + hr = DllRegisterServerDoc_Impl( nMode, bForAllUsers, n32KeyAccess ); + + return hr; +} + + +// DllUnregisterServerDoc - Removes entries from the system registry + +static HRESULT DllUnregisterServerDoc_Impl( int nMode, bool bForAllUsers, REGSAM nKeyAccess ) +{ + char aSubKey[513]; + const char* aPrefix = aLocalPrefix; // bForAllUsers ? "" : aLocalPrefix; + + Status s(false); // no throw + for (int ind = 0; ind < SUPPORTED_MSEXT_NUM; ind++) + { + if (nForMSModes[ind] & nMode) + { + DWORD nSubKeys = 0, nValues = 0; + Status s1(false); // no throw + { + wsprintfA(aSubKey, "%sMIME\\DataBase\\Content Type\\%s", aPrefix, aMSMimeType[ind]); + HRegKey hkey; + if (s1.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr))) + { + s.upd(RegDeleteValueA(hkey, "Extension")); + s.upd(RegDeleteValueA(hkey, "CLSID")); + s1.upd(RegQueryInfoKeyA(hkey, nullptr, nullptr, nullptr, &nSubKeys, nullptr, + nullptr, &nValues, nullptr, nullptr, nullptr, nullptr)); + } + } + if (s1 && !nSubKeys && !nValues) + DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess); + s.upd(s1.get()); + + Status s2(false); // no throw + { + wsprintfA(aSubKey, "%s%s", aPrefix, aMSFileExt[ind]); + HRegKey hkey; + if (s2.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr))) + { + s.upd(RegDeleteValueA(hkey, "Content Type")); + s2.upd(RegQueryInfoKeyA(hkey, nullptr, nullptr, nullptr, &nSubKeys, nullptr, + nullptr, &nValues, nullptr, nullptr, nullptr, nullptr)); + } + } + if (s2 && !nSubKeys && !nValues) + DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess); + s.upd(s2.get()); + } + } + + return HRESULT_FROM_WIN32(s.get()); +} + +STDAPI DllUnregisterServerDoc( int nMode, BOOL bForAllUsers, BOOL bFor64Bit ) +{ + HRESULT hr = S_OK; + if ( bFor64Bit ) + hr = DllUnregisterServerDoc_Impl( nMode, bForAllUsers, n64KeyAccess ); + + if ( SUCCEEDED( hr ) ) + hr = DllUnregisterServerDoc_Impl( nMode, bForAllUsers, n32KeyAccess ); + + return hr; +} + + +// DllRegisterServer - regsvr32 entry point + +STDAPI DllRegisterServer() +{ + HRESULT aResult = E_FAIL; + + HMODULE aCurModule{}; + GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + reinterpret_cast<LPCWSTR>(&DllRegisterServer), &aCurModule); + if( aCurModule ) + { + wchar_t pProgramPath[1024]; + wchar_t* pPathEnd = nullptr; + DWORD nLen = GetModuleFileNameW( aCurModule, pProgramPath, SAL_N_ELEMENTS(pProgramPath) ); + if ( nLen && nLen < SAL_N_ELEMENTS(pProgramPath) ) + pPathEnd = wcsrchr(pProgramPath, '\\'); + if (pPathEnd) + { + *pPathEnd = 0; + aResult = DllRegisterServerNative( 31, TRUE, bX64, pProgramPath ); + if( SUCCEEDED( aResult ) ) + aResult = DllRegisterServerDoc( 31, TRUE, bX64 ); + else + { + aResult = DllRegisterServerNative( 31, FALSE, bX64, pProgramPath ); + if( SUCCEEDED( aResult ) ) + aResult = DllRegisterServerDoc( 31, FALSE, bX64 ); + } + } + } + + return aResult; +} + + +// DllUnregisterServer - regsvr32 entry point + +STDAPI DllUnregisterServer() +{ + DllUnregisterServerDoc( 63, FALSE, bX64 ); + DllUnregisterServerNative( 63, FALSE, bX64 ); + DllUnregisterServerDoc( 63, TRUE, bX64 ); + return DllUnregisterServerNative( 63, TRUE, bX64 ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/so_activex.def b/extensions/source/activex/so_activex.def new file mode 100644 index 000000000..9f81e7917 --- /dev/null +++ b/extensions/source/activex/so_activex.def @@ -0,0 +1,13 @@ +; iervp.def : Declares the module parameters.
+
+LIBRARY
+
+EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllGetClassObject PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
+ DllRegisterServerNative PRIVATE
+ DllRegisterServerDoc PRIVATE
+ DllUnregisterServerNative PRIVATE
+ DllUnregisterServerDoc PRIVATE
diff --git a/extensions/source/activex/so_activex.idl b/extensions/source/activex/so_activex.idl new file mode 100644 index 000000000..a84dde219 --- /dev/null +++ b/extensions/source/activex/so_activex.idl @@ -0,0 +1,230 @@ +/* -*- 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 . + */ + +// so_activex.idl : IDL source for so_activex.dll + + +// This file will be processed by the MIDL tool to +// produce the type library (so_activex.tlb) and marshalling code. + +import "oaidl.idl"; +import "ocidl.idl"; +#include <olectl.h> + + + [ + object, + uuid(DACF7E3F-626B-4BF9-964B-F4910C843711), + dual, + helpstring("ISOActiveX Interface"), + pointer_default(unique) + ] + interface ISOActiveX : IDispatch + { + }; + +[ + object, + uuid(BF5D10F3-8A10-4A0B-B150-2B6AA2D7E118), + dual, + helpstring("ISOComWindowPeer Interface"), + pointer_default(unique) +] +interface ISOComWindowPeer : IDispatch +{ + [id(1), helpstring("method getWindowHandle")] + HRESULT getWindowHandle( [in] SAFEARRAY(VARIANT) procId, + [in] short s, + [out,retval] long* ret); + + [id(2), helpstring("method getToolkit")] + HRESULT getToolkit( [out,retval] IDispatch** retVal ); + + [id(3), helpstring("method setPointer")] + HRESULT setPointer( [in] IDispatch* xPointer ); + + [id(4), helpstring("method setBackground")] + HRESULT setBackground( [in] int nColor ); + + [id(5), helpstring("method invalidate")] + HRESULT invalidate( [in] short ); + + [id(6), helpstring("method invalidateRect")] + HRESULT invalidateRect( [in] IDispatch* aRect, [in] short nFlags ); + + [id(7), helpstring("method dispose")] + HRESULT dispose(); + + [id(8), helpstring("method addEventListener")] + HRESULT addEventListener( [in] IDispatch* xListener ); + + [id(9), helpstring("method removeEventListener")] + HRESULT removeEventListener( [in] IDispatch* xListener ); + + [propget, id(10), helpstring("property_implementedInterfaces")] + HRESULT Bridge_implementedInterfaces([out, retval] SAFEARRAY(BSTR) *pVal); +}; + +[ + object, + uuid(9337694C-B27D-4384-95A4-9D8E0EABC9E5), + dual, + helpstring("ISODispatchInterceptor Interface"), + pointer_default(unique) +] +interface ISODispatchInterceptor : IDispatch +{ +//com.sun.star.frame.XDispatchProviderInterceptor + + [id(1), helpstring("method getSlaveDispatchProvider")] + HRESULT getSlaveDispatchProvider( [out,retval] IDispatch** retVal ); + + [id(2), helpstring("method setSlaveDispatchProvider")] + HRESULT setSlaveDispatchProvider( [in] IDispatch* xNewDispatchProvider ); + + [id(3), helpstring("method getMasterDispatchProvider")] + HRESULT getMasterDispatchProvider( [out,retval] IDispatch** retVal ); + + [id(4), helpstring("method setMasterDispatchProvider")] + HRESULT setMasterDispatchProvider( [in] IDispatch* xNewSupplier ); + +// com.sun.star.frame.XDispatchProvider + + [id(5), helpstring("method queryDispatch")] + HRESULT queryDispatch( [in] IDispatch* aURL, + [in] BSTR aTargetFrameName, + [in] long nSearchFlags, + [out,retval] IDispatch** retVal ); + + [id(6), helpstring("method queryDispatches")] + HRESULT queryDispatches( [in] SAFEARRAY(IDispatch*) aDescripts, + [out,retval] SAFEARRAY(VARIANT)* retVal ); + + +// com.sun.star.frame.XDispatch + + [id(7), helpstring("method dispatch")] + HRESULT dispatch( [in] IDispatch* aURL, + [in] SAFEARRAY(VARIANT) aArgs ); + + [id(8), helpstring("method addStatusListener")] + HRESULT addStatusListener( [in] IDispatch* xControl, + [in] IDispatch* aURL ); + + [id(9), helpstring("method removeStatusListener")] + HRESULT removeStatusListener( [in] IDispatch* xControl, + [in] IDispatch* aURL ); + +// com.sun.star.frame.XInterceptorInfo + + + [id(10), helpstring("method getInterceptedURLs")] + HRESULT getInterceptedURLs( [out,retval] SAFEARRAY(BSTR)* pVal ); + +// the common UNO-COM staff + [propget, id(11), helpstring("property_implementedInterfaces")] + HRESULT Bridge_implementedInterfaces([out, retval] SAFEARRAY(BSTR) *pVal); + +}; + + + + +[ + object, + uuid(029E9F1E-2B3F-4297-9160-8197DE7ED54F), + dual, + helpstring("ISOActionsApproval Interface"), + pointer_default(unique) +] +interface ISOActionsApproval : IDispatch +{ +//com.sun.star.embed.XActionsApproval + + [id(1), helpstring("method approveAction")] + HRESULT approveAction( [in] long aActionID, + [out,retval] boolean* pbApproval ); + +// the common UNO-COM staff + [propget, id(2), helpstring("property_implementedInterfaces")] + HRESULT Bridge_implementedInterfaces([out, retval] SAFEARRAY(BSTR) *pVal); +}; + + + +[ + uuid(61FA3F13-8061-4796-B055-3697ED28CB38), + version(1.0), + helpstring("so_activex 1.0 Type Library") +] +library SO_ACTIVEXLib +{ + importlib("stdole32.tlb"); + importlib("stdole2.tlb"); + + [ + uuid(7F760565-5719-4F04-BA86-112C474B10EA), + helpstring("_ISOActiveXEvents Interface") + ] + dispinterface _ISOActiveXEvents + { + properties: + methods: + }; + + [ + uuid(67F2A879-82D5-4A6D-8CC5-FFB3C114B69D), + helpstring("SOActiveX Class") + ] + coclass SOActiveX + { + [default] interface ISOActiveX; + [default, source] dispinterface _ISOActiveXEvents; + }; + + [ + uuid(EE51BD3E-8BB6-4FB8-B319-F65B1BE3B21D), + helpstring("SOComWindowPeer Class") + ] + coclass SOComWindowPeer + { + [default] interface ISOComWindowPeer; + }; + + [ + uuid(C5D6D568-57DA-4D6C-819A-451CB565E682), + helpstring("SODispatchInterceptor Class") + ] + coclass SODispatchInterceptor + { + [default] interface ISODispatchInterceptor; + }; + + [ + uuid(9F3697AC-7A18-4335-AF0A-65FAC2C35CC1), + helpstring("SOActionsApproval Class") + ] + coclass SOActionsApproval + { + [default] interface ISOActionsApproval; + }; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/so_activex.rc b/extensions/source/activex/so_activex.rc new file mode 100644 index 000000000..3891fa965 --- /dev/null +++ b/extensions/source/activex/so_activex.rc @@ -0,0 +1,124 @@ +/* + * 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 . + */ + +//Microsoft Developer Studio generated resource script. + +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS + + +// Generated from the TEXTINCLUDE 2 resource. + +#include <winresrc.h> +#define LB_ADDSTRING (WM_USER+1) +#define CB_ADDSTRING (WM_USER+3) +#define IDC_STATIC (-1) + + +#undef APSTUDIO_READONLY_SYMBOLS + + +// Russian resources + +//#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +//#ifdef _WIN32 +//LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +//#pragma code_page(1251) +//#endif //_WIN32 + + + +// Bitmap + + +//IDB_SOACTIVEX BITMAP DISCARDABLE "soacti.bmp" + + + + +// REGISTRY + + +IDR_SOACTIVEX REGISTRY DISCARDABLE "SOActiveX.rgs" +IDR_SOCOMWINDOWPEER REGISTRY DISCARDABLE "SOComWindowPeer.rgs" +IDR_SODISPATCHINTERCEPTOR REGISTRY DISCARDABLE "SODispatchInterceptor.rgs" +//#endif // Russian resources + + + + +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED + + +// TEXTINCLUDE + + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "1 TYPELIB ""so_activex.tlb""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + + +// String Table + + +STRINGTABLE DISCARDABLE +BEGIN + IDS_PROJNAME "so_activex" +END + +#endif // English (U.S.) resources + + + + +#ifndef APSTUDIO_INVOKED + + +// Generated from the TEXTINCLUDE 3 resource. + + +1 TYPELIB SO_ACTIVEX_TLB + + +#endif // not APSTUDIO_INVOKED + |